Merge lp:~vanvugt/compiz/untest into lp:compiz/0.9.9
- untest
- Merge into 0.9.9
Status: | Merged |
---|---|
Approved by: | Daniel van Vugt |
Approved revision: | 3455 |
Merged at revision: | 3455 |
Proposed branch: | lp:~vanvugt/compiz/untest |
Merge into: | lp:compiz/0.9.9 |
Diff against target: |
352 lines (+336/-0) 3 files modified
tests/system/CMakeLists.txt (+1/-0) tests/system/untest/CMakeLists.txt (+11/-0) tests/system/untest/untest.c (+324/-0) |
To merge this branch: | bzr merge lp:~vanvugt/compiz/untest |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sam Spilsbury | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+133210@code.launchpad.net |
Commit message
Introducing untest, the Unredirect Fullscreen Windows Stress Tester.
Already I can use it to reliably crash X on my i965/precise desktop.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3455
http://
Executed test runs:
SUCCESS: http://
Daniel van Vugt (vanvugt) wrote : | # |
1. Yes, it's intentional to not talk to compiz directly. It's cleaner that way. I was told already by Martin/Thomi that I can expect to have compiz running already in QA. And soon that will include unredirection enabled by default. I've already got Martin started trying to get performance testing automated using some benchmarks and games in the lab. This will be an addition to that.
2. Yes it belongs in the compiz source tree because it's testing for a bug that only happens with compiz (as far as we care/know), and its behaviour is directly linked to the expected behaviour of compiz. Even if the bugs occurred with other compositing window managers that did unredirection, the design of untest is specifically focussed on compiz.
3. Nice idea to Redirect/Unredirect from the test itself. But it's an enhancement for later and doesn't invalidate this proposal.
Sam Spilsbury (smspillaz) wrote : | # |
OK for now. Please look into automating the test component.
Daniel van Vugt (vanvugt) wrote : | # |
I'm not sure who else's approval we're waiting for... ?
Preview Diff
1 | === modified file 'tests/system/CMakeLists.txt' |
2 | --- tests/system/CMakeLists.txt 2012-09-18 10:45:43 +0000 |
3 | +++ tests/system/CMakeLists.txt 2012-11-07 10:50:25 +0000 |
4 | @@ -1,1 +1,2 @@ |
5 | add_subdirectory (xorg-gtest) |
6 | +add_subdirectory (untest) |
7 | |
8 | === added directory 'tests/system/untest' |
9 | === added file 'tests/system/untest/CMakeLists.txt' |
10 | --- tests/system/untest/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
11 | +++ tests/system/untest/CMakeLists.txt 2012-11-07 10:50:25 +0000 |
12 | @@ -0,0 +1,11 @@ |
13 | + |
14 | +cmake_minimum_required (VERSION 2.6) |
15 | + |
16 | +include (FindPkgConfig) |
17 | +pkg_search_module (GTK REQUIRED gtk+-3.0) |
18 | +pkg_search_module (GL REQUIRED gl) |
19 | + |
20 | +add_executable (untest untest.c) |
21 | +include_directories (${GTK_INCLUDE_DIRS} ${GL_INCLUDE_DIRS}) |
22 | +link_directories (${GTK_LIBRARY_DIRS} ${GL_LIBRARY_DIRECTORIES}) |
23 | +target_link_libraries (untest ${GTK_LIBRARIES} ${GL_LIBRARIES}) |
24 | |
25 | === added file 'tests/system/untest/untest.c' |
26 | --- tests/system/untest/untest.c 1970-01-01 00:00:00 +0000 |
27 | +++ tests/system/untest/untest.c 2012-11-07 10:50:25 +0000 |
28 | @@ -0,0 +1,324 @@ |
29 | +/* |
30 | + * Unredirect Fullscreen Windows Stress Tester |
31 | + * |
32 | + * Copyright (C) 2012 Canonical Ltd. |
33 | + * Author: Daniel van Vugt <daniel.van.vugt@canonical.com> |
34 | + * |
35 | + * This program is free software; you can redistribute it and/or |
36 | + * modify it under the terms of the GNU General Public License |
37 | + * as published by the Free Software Foundation; either version 2 |
38 | + * of the License, or (at your option) any later version. |
39 | + * |
40 | + * This program is distributed in the hope that it will be useful, |
41 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
42 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
43 | + * GNU General Public License for more details. |
44 | + * |
45 | + * You should have received a copy of the GNU General Public License |
46 | + * along with this program; if not, write to the Free Software |
47 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
48 | + * Boston, MA 02110-1301, USA. |
49 | + */ |
50 | + |
51 | +#include <gtk/gtk.h> |
52 | +#include <gdk/gdkx.h> |
53 | +#include <GL/glx.h> |
54 | + |
55 | +#define SECONDS 1000 |
56 | +#define MINUTES 60000 |
57 | + |
58 | +#define FPS 30 |
59 | +#define CYCLE_PERIOD 2 /* seconds */ |
60 | +#define FULLSCREEN_PERIOD (3 * SECONDS) |
61 | +#define DIALOG_PERIOD (7 * SECONDS) |
62 | + |
63 | +#define PADDING 20 |
64 | + |
65 | +#define RED {0, 0xffff, 0x0000, 0x0000} |
66 | +#define YELLOW {0, 0xffff, 0xffff, 0x0000} |
67 | +#define GREEN {0, 0x0000, 0xffff, 0x0000} |
68 | +#define CYAN {0, 0x0000, 0xffff, 0xffff} |
69 | +#define BLUE {0, 0x0000, 0x0000, 0xffff} |
70 | +#define MAGENTA {0, 0xffff, 0x0000, 0xffff} |
71 | + |
72 | +static const char *app_title = "Unredirect Fullscreen Windows Stress Tester"; |
73 | +static const char *copyright = "Copyright (c) 2012 Canonical Ltd."; |
74 | +static gint test_duration = 120; /* seconds */ |
75 | +static guint64 start_time = 0; |
76 | +static GLXWindow glxwin = None; |
77 | +static GtkButton *button; |
78 | + |
79 | +static void blend (guint16 scale, const GdkColor *a, const GdkColor *b, |
80 | + GdkColor *c) |
81 | +{ |
82 | + unsigned long src = 0xffff - scale; |
83 | + unsigned long dest = scale; |
84 | + c->pixel = 0; |
85 | + c->red = (guint16)((src * a->red + dest * b->red) / 0xffff); |
86 | + c->green = (guint16)((src * a->green + dest * b->green) / 0xffff); |
87 | + c->blue = (guint16)((src * a->blue + dest * b->blue) / 0xffff); |
88 | +} |
89 | + |
90 | +static gboolean cycle_color (gpointer data) |
91 | +{ |
92 | + static const GdkColor color_stop[] = |
93 | + {RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA}; |
94 | + static const int color_stops = sizeof(color_stop)/sizeof(color_stop[0]); |
95 | + static guint16 pos = 0; |
96 | + guint16 scale; |
97 | + GtkWindow *win = GTK_WINDOW (data); |
98 | + int from, to; |
99 | + GdkColor color; |
100 | + |
101 | + pos = (pos + 0xffff / (FPS * CYCLE_PERIOD)) & 0xffff; |
102 | + from = (pos * color_stops) >> 16; |
103 | + to = (from + 1) % color_stops; |
104 | + scale = (pos * color_stops) & 0xffff; |
105 | + blend (scale, color_stop+from, color_stop+to, &color); |
106 | + |
107 | + if (glxwin == None) |
108 | + { |
109 | + gtk_widget_modify_bg (GTK_WIDGET (win), GTK_STATE_NORMAL, &color); |
110 | + } |
111 | + else |
112 | + { |
113 | + glClearColor (color.red / 65535.0f, |
114 | + color.green / 65535.0f, |
115 | + color.blue / 65535.0f, |
116 | + 1.0); |
117 | + glClear (GL_COLOR_BUFFER_BIT); |
118 | + glFinish (); |
119 | + } |
120 | + |
121 | + return TRUE; |
122 | +} |
123 | + |
124 | +static gboolean on_redraw (GtkWidget *widget, void *cr, gpointer data) |
125 | +{ |
126 | + GtkProgressBar *b = GTK_PROGRESS_BAR (data); |
127 | + guint64 elapsed = g_get_real_time () - start_time; |
128 | + gtk_progress_bar_set_fraction (b, |
129 | + (float)elapsed / (1000000 * test_duration)); |
130 | + g_print ("\r%d%% ", (int)(elapsed / (10000 * test_duration))); |
131 | + return FALSE; |
132 | +} |
133 | + |
134 | +static gboolean toggle_fullscreen (gpointer data) |
135 | +{ |
136 | + static gboolean is_fullscreen = FALSE; |
137 | + GtkWindow *w = GTK_WINDOW (data); |
138 | + is_fullscreen = !is_fullscreen; |
139 | + if (is_fullscreen) |
140 | + gtk_window_fullscreen (w); |
141 | + else |
142 | + gtk_window_unfullscreen (w); |
143 | + return TRUE; |
144 | +} |
145 | + |
146 | +static gboolean toggle_dialog (gpointer data) |
147 | +{ |
148 | + static gboolean visible = FALSE; |
149 | + GtkWindow *dialog = GTK_WINDOW (data); |
150 | + visible = !visible; |
151 | + gtk_widget_set_visible (GTK_WIDGET (dialog), visible); |
152 | + return TRUE; |
153 | +} |
154 | + |
155 | +static void close_window (GtkWidget *widget, gpointer user_data) |
156 | +{ |
157 | + gtk_main_quit (); |
158 | + g_print ("\rYou're a quitter. No test results for you.\n"); |
159 | +} |
160 | + |
161 | +static gboolean end_test (gpointer data) |
162 | +{ |
163 | + gtk_main_quit (); |
164 | + g_print ("\rCongratulations! Nothing crashed.\n"); |
165 | + return FALSE; |
166 | +} |
167 | + |
168 | +static gboolean init_opengl (GtkWindow *win) |
169 | +{ |
170 | + gboolean ret = FALSE; |
171 | + static const int attr[] = |
172 | + { |
173 | + GLX_X_RENDERABLE, True, |
174 | + GLX_DOUBLEBUFFER, False, |
175 | + None |
176 | + }; |
177 | + Display *dpy = gdk_x11_get_default_xdisplay (); |
178 | + int screen = gdk_x11_get_default_screen (); |
179 | + int nfb; |
180 | + GLXFBConfig *fb = glXChooseFBConfig (dpy, screen, attr, &nfb); |
181 | + |
182 | + if (fb != NULL && nfb > 0) |
183 | + { |
184 | + GdkWindow *gdkwin = gtk_widget_get_window (GTK_WIDGET (win)); |
185 | + Window xwin = gdk_x11_window_get_xid (gdkwin); |
186 | + glxwin = glXCreateWindow (dpy, fb[0], xwin, NULL); |
187 | + if (glxwin != None) |
188 | + { |
189 | + GLXContext ctx = glXCreateNewContext (dpy, fb[0], GLX_RGBA_TYPE, |
190 | + NULL, True); |
191 | + if (ctx != NULL) |
192 | + { |
193 | + if (glXMakeContextCurrent (dpy, glxwin, glxwin, ctx)) |
194 | + { |
195 | + const char *vendor = (const char*) |
196 | + glGetString (GL_VENDOR); |
197 | + const char *renderer = (const char*) |
198 | + glGetString (GL_RENDERER); |
199 | + const char *version = (const char*) |
200 | + glGetString (GL_VERSION); |
201 | + g_print ("GL Vendor: %s\n" |
202 | + "GL Renderer: %s\n" |
203 | + "GL Version: %s\n" |
204 | + "\n", |
205 | + vendor != NULL ? vendor : "?", |
206 | + renderer != NULL ? renderer : "?", |
207 | + version != NULL ? version : "?"); |
208 | + ret = TRUE; |
209 | + } |
210 | + else |
211 | + { |
212 | + g_warning ("glXMakeContextCurrent failed. " |
213 | + "OpenGL won't be used.\n"); |
214 | + |
215 | + } |
216 | + } |
217 | + } |
218 | + else |
219 | + { |
220 | + g_warning ("glXCreateWindow failed. OpenGL won't be used.\n"); |
221 | + } |
222 | + XFree (fb); |
223 | + } |
224 | + else |
225 | + { |
226 | + g_warning ("glXChooseFBConfig returned nothing. " |
227 | + "OpenGL won't be used.\n"); |
228 | + } |
229 | + |
230 | + return ret; |
231 | +} |
232 | + |
233 | +int main (int argc, char *argv[]) |
234 | +{ |
235 | + static gboolean gl_disabled = FALSE; |
236 | + static GOptionEntry custom_options[] = |
237 | + { |
238 | + { |
239 | + "disable-opengl", |
240 | + 'd', |
241 | + 0, |
242 | + G_OPTION_ARG_NONE, |
243 | + &gl_disabled, |
244 | + "Disable OpenGL rendering. Use GTK only.", |
245 | + NULL |
246 | + }, |
247 | + { |
248 | + "test-duration", |
249 | + 't', |
250 | + 0, |
251 | + G_OPTION_ARG_INT, |
252 | + &test_duration, |
253 | + "How long the test lasts (default 120 seconds)", |
254 | + "SECONDS" |
255 | + }, |
256 | + { |
257 | + NULL, |
258 | + 0, |
259 | + 0, |
260 | + G_OPTION_ARG_NONE, |
261 | + NULL, |
262 | + NULL, |
263 | + NULL |
264 | + } |
265 | + }; |
266 | + GtkWindow *win; |
267 | + GtkWindow *dialog; |
268 | + GtkLabel *label; |
269 | + GtkBox *vbox; |
270 | + GtkBox *hbox; |
271 | + GtkAlignment *align; |
272 | + GtkProgressBar *bar; |
273 | + |
274 | + g_print ("%s\n" |
275 | + "%s\n" |
276 | + "\n", |
277 | + app_title, copyright); |
278 | + |
279 | + if (!gtk_init_with_args (&argc, &argv, NULL, custom_options, NULL, NULL)) |
280 | + { |
281 | + g_warning ("Invalid options? Try: %s --help\n", argv[0]); |
282 | + return 1; |
283 | + } |
284 | + |
285 | + win = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL)); |
286 | + gtk_window_set_title (win, app_title); |
287 | + gtk_window_set_default_size (win, 300, 300); |
288 | + gtk_window_set_position (win, GTK_WIN_POS_CENTER); |
289 | + gtk_widget_show (GTK_WIDGET (win)); |
290 | + |
291 | + align = GTK_ALIGNMENT (gtk_alignment_new (0.5f, 1.0f, 0.5f, 0.1f)); |
292 | + gtk_container_add (GTK_CONTAINER (win), GTK_WIDGET (align)); |
293 | + gtk_widget_show (GTK_WIDGET (align)); |
294 | + |
295 | + vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, PADDING)); |
296 | + gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (vbox)); |
297 | + gtk_widget_show (GTK_WIDGET (vbox)); |
298 | + |
299 | + hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, PADDING)); |
300 | + gtk_box_set_homogeneous (hbox, FALSE); |
301 | + gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (hbox)); |
302 | + gtk_widget_show (GTK_WIDGET (hbox)); |
303 | + |
304 | + bar = GTK_PROGRESS_BAR (gtk_progress_bar_new ()); |
305 | + gtk_progress_bar_set_text (bar, NULL); |
306 | + gtk_progress_bar_set_show_text (bar, TRUE); |
307 | + gtk_container_add (GTK_CONTAINER (hbox), GTK_WIDGET (bar)); |
308 | + gtk_box_set_child_packing (hbox, GTK_WIDGET (bar), TRUE, TRUE, 0, |
309 | + GTK_PACK_START); |
310 | + gtk_widget_show (GTK_WIDGET (bar)); |
311 | + |
312 | + button = GTK_BUTTON (gtk_button_new_with_label ("Cancel")); |
313 | + gtk_container_add (GTK_CONTAINER (hbox), GTK_WIDGET (button)); |
314 | + gtk_box_set_child_packing (hbox, GTK_WIDGET (button), FALSE, FALSE, 0, |
315 | + GTK_PACK_END); |
316 | + gtk_widget_show (GTK_WIDGET (button)); |
317 | + |
318 | + dialog = GTK_WINDOW (gtk_window_new (GTK_WINDOW_POPUP)); |
319 | + gtk_window_set_transient_for (dialog, win); |
320 | + gtk_window_set_default_size (dialog, 100, 100); |
321 | + gtk_window_set_position (dialog, GTK_WIN_POS_CENTER); |
322 | + |
323 | + label = GTK_LABEL (gtk_label_new ("Popup!")); |
324 | + gtk_label_set_justify (label, GTK_JUSTIFY_CENTER); |
325 | + gtk_container_add (GTK_CONTAINER (dialog), GTK_WIDGET (label)); |
326 | + gtk_widget_show (GTK_WIDGET (label)); |
327 | + |
328 | + gtk_widget_realize (GTK_WIDGET (win)); |
329 | + if (!gl_disabled) |
330 | + init_opengl (win); |
331 | + |
332 | + /* XXX For now, hide the widgets in OpenGL mode. People will think the |
333 | + flickering is a bug */ |
334 | + if (glxwin) |
335 | + gtk_widget_hide (GTK_WIDGET (align)); |
336 | + |
337 | + g_timeout_add (1000 / FPS, cycle_color, win); |
338 | + g_timeout_add (FULLSCREEN_PERIOD, toggle_fullscreen, win); |
339 | + g_timeout_add (test_duration * SECONDS, end_test, NULL); |
340 | + g_timeout_add (DIALOG_PERIOD, toggle_dialog, dialog); |
341 | + |
342 | + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (close_window), |
343 | + NULL); |
344 | + g_signal_connect (G_OBJECT (win), "draw", G_CALLBACK (on_redraw), bar); |
345 | + g_signal_connect (G_OBJECT (win), "destroy", G_CALLBACK (close_window), |
346 | + NULL); |
347 | + |
348 | + start_time = g_get_real_time (); |
349 | + gtk_main (); |
350 | + |
351 | + return 0; |
352 | +} |
Looks like a useful tool, I have some questions though:
1. It seems like the purpose of this code is to throw up a window that the user can make fullscreen and unfullscreen (and/or pop up a dialog to redirect). That doesn't really guarantee that you're actually testing fullscreen window unredirection, because you need to be running compiz for it to work (and that just assumes that fullscreen window unredirection works in compiz). Maybe add a warning and/or start compiz if not started
2. Does it belong in the compiz source tree? Seems like it might be better as a separate driver test suite.
On a much broader note:
I think that providing integration tests like these for the drivers would be very useful, however, their use would just go up ten-fold if we could automate them and run them as a job in the QA lab.
Have you considered making a standalone integration test that doesn't depend on a running instance of compiz or anything like that? That makes it far easier for developers to rule out compiz using the API incorrectly as the problem. For example, the test would:
1. create a window ectSubWindows irectWindow on the opengl subwindow ectWindow on the opengl subwindow
2. create a subwindow with an opengl visual
3. call XCompositeRedir
4. call XCompositeUnred
5. call XCompostieRedir
You can then effectively script it to redirect and unredirect the subwindow as much as you want.
It might be that drivers only get upset when a composite overlay window is in use, so it might be worth looking into automating it that way.