Merge lp:~vanvugt/compiz/untest into lp:compiz/0.9.9

Proposed by Daniel van Vugt on 2012-11-07
Status: Merged
Approved by: Daniel van Vugt on 2012-11-08
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
Reviewer Review Type Date Requested Status
Sam Spilsbury 2012-11-07 Approve on 2012-11-08
PS Jenkins bot (community) continuous-integration Approve on 2012-11-07
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.

To post a comment you must log in.
Sam Spilsbury (smspillaz) wrote :

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
2. create a subwindow with an opengl visual
3. call XCompositeRedirectSubWindows
4. call XCompositeUnredirectWindow on the opengl subwindow
5. call XCompostieRedirectWindow on the opengl subwindow

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.

review: Needs Information
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
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.

review: Approve
Daniel van Vugt (vanvugt) wrote :

I'm not sure who else's approval we're waiting for... ?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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+}

Subscribers

People subscribed via source and target branches