Merge lp:~alan-griffiths/unity-system-compositor/spinner-rework into lp:unity-system-compositor

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: 240
Merged at revision: 213
Proposed branch: lp:~alan-griffiths/unity-system-compositor/spinner-rework
Merge into: lp:unity-system-compositor
Prerequisite: lp:~mir-team/unity-system-compositor/respond-to-event-cleanup
Diff against target: 1103 lines (+521/-368)
7 files modified
spinner/CMakeLists.txt (+1/-1)
spinner/eglapp.cpp (+106/-231)
spinner/eglapp.h (+4/-17)
spinner/eglspinner.cpp (+146/-118)
spinner/miregl.cpp (+198/-0)
spinner/miregl.h (+64/-0)
tests/integration-tests/test_dbus_event_loop.cpp (+2/-1)
To merge this branch: bzr merge lp:~alan-griffiths/unity-system-compositor/spinner-rework
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alexandros Frantzis (community) Approve
Kevin DuBois (community) Approve
Review via email: mp+260148@code.launchpad.net

Commit message

Rework of spinner app to avoid deprecated Mir APIs, correctly set fullscreen state and support multiple outputs.

Description of the change

Rework of spinner app to avoid deprecated Mir APIs, correctly set fullscreen state and support multiple outputs.

To post a comment you must log in.
Revision history for this message
Kevin DuBois (kdub) wrote :

Looks like a good translation of the existing code, but some things could use fixing (esp the resource cleanup)

887+ eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglctx);
Unless theres a reason to keep the context current, the line should be:
eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

pre-existing:
862+ eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ctxattribs);
874+ auto const eglsurface = eglCreateWindowSurface(
resources should be destroyed with eglDestroySurface and eglDestroyContext

847+ if (!eglInitialize(egldisplay, NULL, NULL))
would be good to check that the version is 1.4 (major == 1) && (minor == 4)

nits: (although, maybe not nits for the USC style guide, not sure where to find that)

515+const char vShaderSrcSpinner[] =
516+ "attribute vec4 vPosition; \n"
526+const char fShaderSrcGlow[] =
527+ "precision mediump float; \n"
spacing

651,652,656-660: c-casts, (although not sure if thats a usc policy)

648+ for (auto const& surface : surfaces)
braces for multiline statement following

Revision history for this message
Kevin DuBois (kdub) wrote :

lgtm

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

[ RUN ] ADBusEventLoop.handles_reply_timeouts
/tmp/buildd/unity-system-compositor-0.0.5+15.04.20150430bzr236pkg0wily4/tests/integration-tests/test_dbus_event_loop.cpp:231: Failure
Value of: delay
Expected: is >= 8-byte object <64-00 00-00 00-00 00-00>
  Actual: 8-byte object <8F-52 F1-05 00-00 00-00>
[ FAILED ] ADBusEventLoop.handles_reply_timeouts (108 ms)

Not code touched by this MP (and can't reproduce locally).

But two failures in a row can't be an accident. Adding a little debug code in the hope of enlightenment.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

[ RUN ] ADBusEventLoop.handles_reply_timeouts
DEBUG delay=99878419 in ms=99, lbound=100
/tmp/buildd/unity-system-compositor-0.0.5+15.04.20150430bzr237pkg0wily5/tests/integration-tests/test_dbus_event_loop.cpp:235: Failure
Value of: delay
Expected: is >= 8-byte object <64-00 00-00 00-00 00-00>
  Actual: 8-byte object <13-06 F4-05 00-00 00-00>
[ FAILED ] ADBusEventLoop.handles_reply_timeouts (107 ms)

Ok, the measured delay is just under the timeout. Which could be because the timeout is enqueued (and therefore could initiate) before noting the start time.

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Not a full review yet:

> Ok, the measured delay is just under the timeout. Which could be because the timeout is
> enqueued (and therefore could initiate) before noting the start time.

This is correct. Thanks for the fix.

> nits: (although, maybe not nits for the USC style guide, not sure where to find that)

Let's just use the Mir style guide for USC (I think most of us have been doing that when updating USC anyway).

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

Nits:

167+ printf("Active output [%u] at (%d, %d) is %dx%d\n",168+ output->output_id,169+ output->position_x, output->position_y,170+ mode.horizontal_resolution, mode.vertical_resolution);

for_each_active_output would be cleaner (i.e. no unexpected side effects) if the print statement was part of the handler (which would then accept a MirOutput const*).

1094+ egl_release_current();

In general, releasing a current context is a pessimization, but not a big deal for the spinner app.

+//#define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f498
+//#define ORANGE 0.866666667f, 0.282352941f, 0.141414141f499
...

We could just remove these. We can look up the ubuntu color scheme definitions again if we want to change colors.

712 glClearColor(BLACK, mir_eglapp_background_opacity);

Pre-existing: not needed. We set the clear color (in the main loop) before we invoke glClear().

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

I've left the colors in the comment as a cheap convenience for a future maintainer.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'spinner/CMakeLists.txt'
2--- spinner/CMakeLists.txt 2014-05-06 20:06:27 +0000
3+++ spinner/CMakeLists.txt 2015-05-28 15:29:59 +0000
4@@ -33,7 +33,7 @@
5
6 link_directories(${MIRCLIENT_LIBRARY_DIRS})
7
8-add_executable(unity-system-compositor-spinner eglapp.c eglapp.h eglspinner.c)
9+add_executable(unity-system-compositor-spinner eglapp.cpp eglapp.h eglspinner.cpp miregl.h miregl.cpp)
10 target_link_libraries(unity-system-compositor-spinner
11 EGL
12 ${CAIRO_LDFLAGS}
13
14=== renamed file 'spinner/eglapp.c' => 'spinner/eglapp.cpp'
15--- spinner/eglapp.c 2015-04-24 12:48:10 +0000
16+++ spinner/eglapp.cpp 2015-05-28 15:29:59 +0000
17@@ -1,5 +1,5 @@
18 /*
19- * Copyright © 2013 Canonical Ltd.
20+ * Copyright © 2013, 2015 Canonical Ltd.
21 *
22 * This program is free software: you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License version 3 as
24@@ -12,145 +12,77 @@
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28- *
29- * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
30 */
31
32 #include "eglapp.h"
33-#include "mir_toolkit/mir_client_library.h"
34-#include <stdio.h>
35-#include <stdlib.h>
36-#include <signal.h>
37-#include <time.h>
38-#include <EGL/egl.h>
39-#include <GLES2/gl2.h>
40+
41+#include "miregl.h"
42+
43+
44
45 float mir_eglapp_background_opacity = 1.0f;
46
47 static const char appname[] = "eglspinner";
48
49-static MirConnection *connection;
50-static MirSurface *surface;
51-static EGLDisplay egldisplay;
52-static EGLSurface eglsurface;
53-static volatile sig_atomic_t running = 0;
54-
55-#define CHECK(_cond, _err) \
56- if (!(_cond)) \
57- { \
58- printf("%s\n", (_err)); \
59- return 0; \
60- }
61-
62-void mir_eglapp_shutdown(void)
63-{
64- eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
65- eglTerminate(egldisplay);
66- mir_surface_release_sync(surface);
67- surface = NULL;
68- mir_connection_release(connection);
69- connection = NULL;
70-}
71-
72-static void shutdown(int signum)
73-{
74- if (running)
75- {
76- running = 0;
77- printf("Signal %d received. Good night.\n", signum);
78- }
79-}
80-
81-mir_eglapp_bool mir_eglapp_running(void)
82-{
83- return running;
84-}
85-
86-void mir_eglapp_swap_buffers(void)
87-{
88- EGLint width, height;
89-
90- if (!running)
91- return;
92-
93- eglSwapBuffers(egldisplay, eglsurface);
94-
95- /*
96- * Querying the surface (actually the current buffer) dimensions here is
97- * the only truly safe way to be sure that the dimensions we think we
98- * have are those of the buffer being rendered to. But this should be
99- * improved in future; https://bugs.launchpad.net/mir/+bug/1194384
100- */
101- if (eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width) &&
102- eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height))
103- {
104- glViewport(0, 0, width, height);
105- }
106-}
107-
108-static void mir_eglapp_handle_event(MirSurface* surface, MirEvent const* ev, void* context)
109-{
110- (void) surface;
111- (void) context;
112- if (mir_event_get_type(ev) == mir_event_type_resize)
113- {
114- MirResizeEvent const* resize = mir_event_get_resize_event(ev);
115- /*
116- * FIXME: https://bugs.launchpad.net/mir/+bug/1194384
117- * It is unsafe to set the width and height here because we're in a
118- * different thread to that doing the rendering. So we either need
119- * support for event queuing (directing them to another thread) or
120- * full single-threaded callbacks. (LP: #1194384).
121- */
122- printf("Resized to %dx%d\n",
123- mir_resize_event_get_width(resize),
124- mir_resize_event_get_height(resize));
125- }
126-}
127-
128-static const MirDisplayOutput *find_active_output(
129- const MirDisplayConfiguration *conf)
130-{
131- const MirDisplayOutput *output = NULL;
132- int d;
133-
134- for (d = 0; d < (int)conf->num_outputs; d++)
135- {
136- const MirDisplayOutput *out = conf->outputs + d;
137-
138- if (out->used &&
139- out->connected &&
140- out->num_modes &&
141- out->current_mode < out->num_modes)
142+
143+namespace
144+{
145+template<typename ActiveOutputHandler>
146+void for_each_active_output(
147+ MirConnection* const connection, ActiveOutputHandler const& handler)
148+{
149+ /* eglapps are interested in the screen size, so
150+ use mir_connection_create_display_config */
151+ MirDisplayConfiguration* display_config =
152+ mir_connection_create_display_config(connection);
153+
154+ for (MirDisplayOutput* output = display_config->outputs;
155+ output != display_config->outputs + display_config->num_outputs;
156+ ++output)
157+ {
158+ if (output->used &&
159+ output->connected &&
160+ output->num_modes &&
161+ output->current_mode < output->num_modes)
162 {
163- output = out;
164- break;
165+ handler(output);
166 }
167 }
168
169- return output;
170-}
171-
172-mir_eglapp_bool mir_eglapp_init(int argc, char *argv[],
173- unsigned int *width, unsigned int *height)
174-{
175- EGLint ctxattribs[] =
176- {
177- EGL_CONTEXT_CLIENT_VERSION, 2,
178- EGL_NONE
179- };
180+ mir_display_config_destroy(display_config);
181+}
182+
183+MirPixelFormat select_pixel_format(MirConnection* connection)
184+{
185+ unsigned int format[mir_pixel_formats];
186+ unsigned int nformats;
187+
188+ mir_connection_get_available_surface_formats(
189+ connection,
190+ (MirPixelFormat*) format,
191+ mir_pixel_formats,
192+ &nformats);
193+
194+ auto const pixel_format = (MirPixelFormat) format[0];
195+
196+ printf("Server supports %d of %d surface pixel formats. Using format: %d\n",
197+ nformats, mir_pixel_formats, pixel_format);
198+
199+ return pixel_format;
200+}
201+}
202+
203+std::vector<std::shared_ptr<MirEglSurface>> mir_eglapp_init(int argc, char *argv[])
204+{
205 MirSurfaceParameters surfaceparm =
206- {
207- "eglappsurface",
208- 256, 256,
209- mir_pixel_format_xbgr_8888,
210- mir_buffer_usage_hardware,
211- mir_display_output_id_invalid
212- };
213- EGLConfig eglconfig;
214- EGLint neglconfigs;
215- EGLContext eglctx;
216- EGLBoolean ok;
217+ {
218+ "eglappsurface",
219+ 0, 0,
220+ mir_pixel_format_xbgr_8888,
221+ mir_buffer_usage_hardware,
222+ mir_display_output_id_invalid
223+ };
224+
225 EGLint swapinterval = 1;
226 char *mir_socket = NULL;
227
228@@ -159,7 +91,7 @@
229 int i;
230 for (i = 1; i < argc; i++)
231 {
232- mir_eglapp_bool help = 0;
233+ bool help = 0;
234 const char *arg = argv[i];
235
236 if (arg[0] == '-')
237@@ -209,10 +141,6 @@
238 }
239 }
240 break;
241- case 'f':
242- *width = 0;
243- *height = 0;
244- break;
245 case 's':
246 {
247 unsigned int w, h;
248@@ -224,8 +152,8 @@
249 }
250 if (sscanf(arg, "%ux%u", &w, &h) == 2)
251 {
252- *width = w;
253- *height = h;
254+ surfaceparm.width = w;
255+ surfaceparm.height = h;
256 }
257 else
258 {
259@@ -259,111 +187,58 @@
260 printf("Usage: %s [<options>]\n"
261 " -b Background opacity (0.0 - 1.0)\n"
262 " -h Show this help text\n"
263- " -f Force full screen\n"
264 " -o ID Force placement on output monitor ID\n"
265 " -n Don't sync to vblank\n"
266 " -m socket Mir server socket\n"
267 " -s WIDTHxHEIGHT Force surface size\n"
268 " -q Quiet mode (no messages output)\n"
269 , argv[0]);
270- return 0;
271+ return {};
272 }
273 }
274 }
275
276- connection = mir_connect_sync(mir_socket, appname);
277- CHECK(mir_connection_is_valid(connection), "Can't get connection");
278-
279- /* eglapps are interested in the screen size, so
280- use mir_connection_create_display_config */
281- MirDisplayConfiguration* display_config =
282- mir_connection_create_display_config(connection);
283-
284- const MirDisplayOutput *output = find_active_output(display_config);
285-
286- if (output == NULL)
287- {
288- printf("No active outputs found.\n");
289- return 0;
290- }
291-
292- const MirDisplayMode *mode = &output->modes[output->current_mode];
293-
294- unsigned int format[mir_pixel_formats];
295- unsigned int nformats;
296-
297- mir_connection_get_available_surface_formats(connection,
298- (MirPixelFormat*) format, mir_pixel_formats, &nformats);
299-
300- surfaceparm.pixel_format = (MirPixelFormat) format[0];
301-
302- printf("Current active output is %dx%d %+d%+d\n",
303- mode->horizontal_resolution, mode->vertical_resolution,
304- output->position_x, output->position_y);
305-
306- surfaceparm.width = *width > 0 ? *width : mode->horizontal_resolution;
307- surfaceparm.height = *height > 0 ? *height : mode->vertical_resolution;
308-
309- mir_display_config_destroy(display_config);
310-
311- printf("Server supports %d of %d surface pixel formats. Using format: %d\n",
312- nformats, mir_pixel_formats, surfaceparm.pixel_format);
313- unsigned int bpp = 8 * MIR_BYTES_PER_PIXEL(surfaceparm.pixel_format);
314- EGLint attribs[] =
315- {
316- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
317- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
318- EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
319- EGL_BUFFER_SIZE, (EGLint) bpp,
320- EGL_NONE
321- };
322-
323- surface = mir_connection_create_surface_sync(connection, &surfaceparm);
324- CHECK(mir_surface_is_valid(surface), "Can't create a surface");
325-
326- mir_surface_set_event_handler(surface, mir_eglapp_handle_event, NULL);
327-
328- egldisplay = eglGetDisplay(
329- (EGLNativeDisplayType) mir_connection_get_egl_native_display(connection));
330- CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay");
331-
332- ok = eglInitialize(egldisplay, NULL, NULL);
333- CHECK(ok, "Can't eglInitialize");
334-
335- ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs);
336- CHECK(ok, "Could not eglChooseConfig");
337- CHECK(neglconfigs > 0, "No EGL config available");
338-
339- eglsurface = eglCreateWindowSurface(egldisplay, eglconfig,
340- (EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(surface)), NULL);
341- CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed");
342-
343- eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT,
344- ctxattribs);
345- CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed");
346-
347- ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx);
348- CHECK(ok, "Can't eglMakeCurrent");
349-
350- signal(SIGINT, shutdown);
351- signal(SIGTERM, shutdown);
352-
353- *width = surfaceparm.width;
354- *height = surfaceparm.height;
355-
356- eglSwapInterval(egldisplay, swapinterval);
357-
358- running = 1;
359-
360- return 1;
361-}
362-
363-struct MirConnection* mir_eglapp_native_connection()
364-{
365- return connection;
366-}
367-
368-struct MirSurface* mir_eglapp_native_surface()
369-{
370- return surface;
371+ MirConnection* const connection{mir_connect_sync(mir_socket, appname)};
372+ if (!mir_connection_is_valid(connection))
373+ throw std::runtime_error("Can't get connection");
374+
375+ auto const pixel_format = select_pixel_format(connection);
376+ surfaceparm.pixel_format = pixel_format;
377+
378+ auto const mir_egl_app = make_mir_eglapp(connection, pixel_format, swapinterval);
379+
380+ std::vector<std::shared_ptr<MirEglSurface>> result;
381+
382+ // If a size has been specified just do that
383+ if (surfaceparm.width && surfaceparm.height)
384+ {
385+ result.push_back(std::make_shared<MirEglSurface>(mir_egl_app, surfaceparm));
386+ return result;
387+ }
388+
389+ // If an output has been specified just do that
390+ if (surfaceparm.output_id != mir_display_output_id_invalid)
391+ {
392+ result.push_back(std::make_shared<MirEglSurface>(mir_egl_app, surfaceparm));
393+ return result;
394+ }
395+
396+ // but normally, we're fullscreen on every active output
397+ for_each_active_output(connection, [&](MirDisplayOutput const* output)
398+ {
399+ auto const& mode = output->modes[output->current_mode];
400+
401+ printf("Active output [%u] at (%d, %d) is %dx%d\n",
402+ output->output_id,
403+ output->position_x, output->position_y,
404+ mode.horizontal_resolution, mode.vertical_resolution);
405+
406+ surfaceparm.output_id = output->output_id;
407+ result.push_back(std::make_shared<MirEglSurface>(mir_egl_app, surfaceparm));
408+ });
409+
410+ if (result.empty())
411+ throw std::runtime_error("No active outputs found.");
412+
413+ return result;
414 }
415
416=== modified file 'spinner/eglapp.h'
417--- spinner/eglapp.h 2014-03-08 22:01:45 +0000
418+++ spinner/eglapp.h 2015-05-28 15:29:59 +0000
419@@ -19,26 +19,13 @@
420 #ifndef __EGLAPP_H__
421 #define __EGLAPP_H__
422
423-#ifdef __cplusplus
424-extern "C" {
425-#endif
426+#include <memory>
427+#include <vector>
428
429-typedef int mir_eglapp_bool;
430-struct MirConnection;
431-struct MirSurface;
432+class MirEglSurface;
433
434 extern float mir_eglapp_background_opacity;
435
436-mir_eglapp_bool mir_eglapp_init(int argc, char *argv[],
437- unsigned int *width, unsigned int *height);
438-void mir_eglapp_swap_buffers(void);
439-mir_eglapp_bool mir_eglapp_running(void);
440-void mir_eglapp_shutdown(void);
441-
442-struct MirConnection* mir_eglapp_native_connection();
443-struct MirSurface* mir_eglapp_native_surface();
444-#ifdef __cplusplus
445-}
446-#endif
447+std::vector<std::shared_ptr<MirEglSurface>> mir_eglapp_init(int argc, char *argv[]);
448
449 #endif
450
451=== renamed file 'spinner/eglspinner.c' => 'spinner/eglspinner.cpp'
452--- spinner/eglspinner.c 2015-05-01 14:16:27 +0000
453+++ spinner/eglspinner.cpp 2015-05-28 15:29:59 +0000
454@@ -18,19 +18,17 @@
455 */
456
457 #include "eglapp.h"
458+#include "miregl.h"
459 #include <assert.h>
460 #include <cairo.h>
461 #include <glib.h>
462-#include <stdio.h>
463 #include <string.h>
464-#include <strings.h>
465-#include <stdlib.h>
466 #include <GLES2/gl2.h>
467-#include <math.h>
468 #include <sys/stat.h>
469 #if HAVE_PROPS
470 #include <hybris/properties/properties.h>
471 #endif
472+#include <signal.h>
473
474 // this is needed for get_gu() to obtain the grid-unit value
475 #define MAX_LENGTH 256
476@@ -63,7 +61,7 @@
477 else
478 {
479 #ifdef HAVE_PROPS
480- char* defaultValue = "";
481+ char const* defaultValue = "";
482 char value[PROP_VALUE_MAX];
483 property_get (PROP_KEY, value, defaultValue);
484 strcat (filename, value);
485@@ -125,26 +123,25 @@
486 }
487
488 // Colours from http://design.ubuntu.com/brand/colour-palette
489-#define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f
490-#define ORANGE 0.866666667f, 0.282352941f, 0.141414141f
491-#define WARM_GREY 0.682352941f, 0.654901961f, 0.623529412f
492-#define COOL_GREY 0.2f, 0.2f, 0.2f
493-#define LIGHT_AUBERGINE 0.466666667f, 0.297297297f, 0.435294118f
494-#define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f
495+//#define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f
496+//#define ORANGE 0.866666667f, 0.282352941f, 0.141414141f
497+//#define WARM_GREY 0.682352941f, 0.654901961f, 0.623529412f
498+//#define COOL_GREY 0.2f, 0.2f, 0.2f
499+//#define LIGHT_AUBERGINE 0.466666667f, 0.297297297f, 0.435294118f
500+//#define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f
501 #define BLACK 0.0f, 0.0f, 0.0f
502-#define WHITE 1.0f, 1.0f, 1.0f
503+//#define WHITE 1.0f, 1.0f, 1.0f
504
505 cairo_surface_t* pngToSurface (const char* filename)
506 {
507- // sanity check
508- if (!filename)
509- return NULL;
510+ if (access(filename, F_OK & R_OK) != 0)
511+ throw std::runtime_error("Failed to load png: " + std::string(filename) + "\n");
512
513 // create surface from PNG
514 cairo_surface_t* surface = NULL;
515 surface = cairo_image_surface_create_from_png (filename);
516 if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
517- return NULL;
518+ throw std::runtime_error("Failed to load png: " + std::string(filename) + "\n");
519
520 return surface;
521 }
522@@ -215,10 +212,10 @@
523 typedef struct _AnimationValues
524 {
525 double lastTimeStamp;
526- double angle;
527- double fadeBackground;
528- double fadeLogo;
529- double fadeGlow;
530+ GLfloat angle;
531+ GLfloat fadeBackground;
532+ GLfloat fadeLogo;
533+ GLfloat fadeGlow;
534 } AnimationValues;
535
536 void
537@@ -264,56 +261,76 @@
538 // anim->fadeLogo -= 1.6f * dt;
539 }
540
541+namespace
542+{
543+const char vShaderSrcSpinner[] =
544+ "attribute vec4 vPosition; \n"
545+ "attribute vec2 aTexCoords; \n"
546+ "uniform float theta; \n"
547+ "varying vec2 vTexCoords; \n"
548+ "void main() \n"
549+ "{ \n"
550+ " float c = cos(theta); \n"
551+ " float s = sin(theta); \n"
552+ " mat2 m; \n"
553+ " m[0] = vec2(c, s); \n"
554+ " m[1] = vec2(-s, c); \n"
555+ " vTexCoords = m * aTexCoords + vec2 (0.5, 0.5); \n"
556+ " gl_Position = vec4(vPosition.xy, -1.0, 1.0); \n"
557+ "} \n";
558+
559+const char fShaderSrcGlow[] =
560+ "precision mediump float; \n"
561+ "varying vec2 vTexCoords; \n"
562+ "uniform sampler2D uSampler; \n"
563+ "uniform float uFadeGlow; \n"
564+ "void main() \n"
565+ "{ \n"
566+ " // swizzle because texture was created with cairo\n"
567+ " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n"
568+ " float r = col.r * uFadeGlow; \n"
569+ " float g = col.g * uFadeGlow; \n"
570+ " float b = col.b * uFadeGlow; \n"
571+ " float a = col.a * uFadeGlow; \n"
572+ " gl_FragColor = vec4(r, g, b, a); \n"
573+ "} \n";
574+
575+const char fShaderSrcLogo[] =
576+ "precision mediump float; \n"
577+ "varying vec2 vTexCoords; \n"
578+ "uniform sampler2D uSampler; \n"
579+ "uniform float uFadeLogo; \n"
580+ "void main() \n"
581+ "{ \n"
582+ " // swizzle because texture was created with cairo\n"
583+ " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n"
584+ " float r = col.r * uFadeLogo; \n"
585+ " float g = col.g * uFadeLogo; \n"
586+ " float b = col.b * uFadeLogo; \n"
587+ " float a = col.a * uFadeLogo; \n"
588+ " gl_FragColor = vec4(r, g, b, a); \n"
589+ "} \n";
590+
591+static volatile sig_atomic_t running = 0;
592+
593+static void shutdown(int signum)
594+{
595+ if (running)
596+ {
597+ running = 0;
598+ printf("Signal %d received. Good night.\n", signum);
599+ }
600+}
601+
602+bool mir_eglapp_running()
603+{
604+ return running;
605+}
606+}
607+
608 int main(int argc, char *argv[])
609+try
610 {
611- const char vShaderSrcSpinner[] =
612- "attribute vec4 vPosition; \n"
613- "attribute vec2 aTexCoords; \n"
614- "uniform float theta; \n"
615- "varying vec2 vTexCoords; \n"
616- "void main() \n"
617- "{ \n"
618- " float c = cos(theta); \n"
619- " float s = sin(theta); \n"
620- " mat2 m; \n"
621- " m[0] = vec2(c, s); \n"
622- " m[1] = vec2(-s, c); \n"
623- " vTexCoords = m * aTexCoords + vec2 (0.5, 0.5); \n"
624- " gl_Position = vec4(vPosition.xy, -1.0, 1.0); \n"
625- "} \n";
626-
627- const char fShaderSrcGlow[] =
628- "precision mediump float; \n"
629- "varying vec2 vTexCoords; \n"
630- "uniform sampler2D uSampler; \n"
631- "uniform float uFadeGlow; \n"
632- "void main() \n"
633- "{ \n"
634- " // swizzle because texture was created with cairo\n"
635- " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n"
636- " float r = col.r * uFadeGlow; \n"
637- " float g = col.g * uFadeGlow; \n"
638- " float b = col.b * uFadeGlow; \n"
639- " float a = col.a * uFadeGlow; \n"
640- " gl_FragColor = vec4(r, g, b, a); \n"
641- "} \n";
642-
643- const char fShaderSrcLogo[] =
644- "precision mediump float; \n"
645- "varying vec2 vTexCoords; \n"
646- "uniform sampler2D uSampler; \n"
647- "uniform float uFadeLogo; \n"
648- "void main() \n"
649- "{ \n"
650- " // swizzle because texture was created with cairo\n"
651- " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n"
652- " float r = col.r * uFadeLogo; \n"
653- " float g = col.g * uFadeLogo; \n"
654- " float b = col.b * uFadeLogo; \n"
655- " float a = col.a * uFadeLogo; \n"
656- " gl_FragColor = vec4(r, g, b, a); \n"
657- "} \n";
658-
659 GLuint prog[2];
660 GLuint texture[2];
661 GLint vpos[2];
662@@ -322,24 +339,20 @@
663 GLint fadeLogo;
664 GLint aTexCoords[2];
665 GLint sampler[2];
666- unsigned int width = 0;
667- unsigned int height = 0;
668-
669- if (!mir_eglapp_init(argc, argv, &width, &height))
670- return 1;
671-
672- double pixelSize = (double) get_gu () * 11.18;
673- double halfRealWidth = ((2.0 / (double) width) * pixelSize) / 2.0;
674- double halfRealHeight = ((2.0 / (double) height) * pixelSize) / 2.0;
675-
676- const GLfloat vertices[] =
677+
678+ auto const surfaces = mir_eglapp_init(argc, argv);
679+
680+ if (!surfaces.size())
681 {
682- halfRealWidth, halfRealHeight,
683- halfRealWidth, -halfRealHeight,
684- -halfRealWidth, halfRealHeight,
685- -halfRealWidth, -halfRealHeight,
686- };
687-
688+ printf("No surfaces created\n");
689+ return EXIT_SUCCESS;
690+ }
691+
692+ running = 1;
693+ signal(SIGINT, shutdown);
694+ signal(SIGTERM, shutdown);
695+
696+ double pixelSize = get_gu() * 11.18;
697 const GLfloat texCoordsSpinner[] =
698 {
699 -0.5f, 0.5f,
700@@ -348,12 +361,8 @@
701 0.5f, -0.5f,
702 };
703
704- prog[0] = createShaderProgram (vShaderSrcSpinner, fShaderSrcGlow);
705- prog[1] = createShaderProgram (vShaderSrcSpinner, fShaderSrcLogo);
706-
707- // setup viewport and projection
708- glClearColor(BLACK, mir_eglapp_background_opacity);
709- glViewport(0, 0, width, height);
710+ prog[0] = createShaderProgram(vShaderSrcSpinner, fShaderSrcGlow);
711+ prog[1] = createShaderProgram(vShaderSrcSpinner, fShaderSrcLogo);
712
713 // setup proper GL-blending
714 glEnable(GL_BLEND);
715@@ -377,8 +386,6 @@
716 uploadTexture(texture[1], PKGDATADIR "/spinner-logo.png");
717
718 // bunch of shader-attributes to enable
719- glVertexAttribPointer(vpos[0], 2, GL_FLOAT, GL_FALSE, 0, vertices);
720- glVertexAttribPointer(vpos[1], 2, GL_FLOAT, GL_FALSE, 0, vertices);
721 glVertexAttribPointer(aTexCoords[0], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner);
722 glVertexAttribPointer(aTexCoords[1], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner);
723 glEnableVertexAttribArray(vpos[0]);
724@@ -388,39 +395,60 @@
725 glActiveTexture(GL_TEXTURE0);
726
727 AnimationValues anim = {0.0, 0.0, 1.0, 0.0, 0.0};
728- GTimer* timer = g_timer_new ();
729+ GTimer* timer = g_timer_new();
730
731 while (mir_eglapp_running())
732 {
733- glClearColor(BLACK, anim.fadeBackground);
734- glClear(GL_COLOR_BUFFER_BIT);
735-
736- // draw glow
737- glUseProgram(prog[0]);
738- glBindTexture(GL_TEXTURE_2D, texture[0]);
739- glUniform1i(sampler[0], 0);
740- glUniform1f(theta, anim.angle);
741- glUniform1f(fadeGlow, anim.fadeGlow);
742- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
743-
744- // draw logo
745- glUseProgram(prog[1]);
746- glBindTexture(GL_TEXTURE_2D, texture[1]);
747- glUniform1i(sampler[1], 0);
748- glUniform1f(theta, anim.angle);
749- glUniform1f(fadeLogo, anim.fadeLogo);
750- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
751+ for (auto const& surface : surfaces)
752+ surface->paint([&](unsigned int width, unsigned int height)
753+ {
754+ GLfloat halfRealWidth = ((2.0 / width) * pixelSize) / 2.0;
755+ GLfloat halfRealHeight = ((2.0 / height) * pixelSize) / 2.0;
756+
757+ const GLfloat vertices[] =
758+ {
759+ halfRealWidth, halfRealHeight,
760+ halfRealWidth, -halfRealHeight,
761+ -halfRealWidth, halfRealHeight,
762+ -halfRealWidth,-halfRealHeight,
763+ };
764+
765+ glVertexAttribPointer(vpos[0], 2, GL_FLOAT, GL_FALSE, 0, vertices);
766+ glVertexAttribPointer(vpos[1], 2, GL_FLOAT, GL_FALSE, 0, vertices);
767+
768+ glViewport(0, 0, width, height);
769+
770+ glClearColor(BLACK, anim.fadeBackground);
771+ glClear(GL_COLOR_BUFFER_BIT);
772+
773+ // draw glow
774+ glUseProgram(prog[0]);
775+ glBindTexture(GL_TEXTURE_2D, texture[0]);
776+ glUniform1i(sampler[0], 0);
777+ glUniform1f(theta, anim.angle);
778+ glUniform1f(fadeGlow, anim.fadeGlow);
779+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
780+
781+ // draw logo
782+ glUseProgram(prog[1]);
783+ glBindTexture(GL_TEXTURE_2D, texture[1]);
784+ glUniform1i(sampler[1], 0);
785+ glUniform1f(theta, anim.angle);
786+ glUniform1f(fadeLogo, anim.fadeLogo);
787+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
788+ });
789
790 // update animation variable
791- updateAnimation (timer, &anim);
792-
793- mir_eglapp_swap_buffers();
794+ updateAnimation(timer, &anim);
795 }
796
797- mir_eglapp_shutdown();
798-
799 glDeleteTextures(2, texture);
800 g_timer_destroy (timer);
801
802- return 0;
803+ return EXIT_SUCCESS;
804 }
805+catch (std::exception const& x)
806+{
807+ printf("%s\n", x.what());
808+ return EXIT_FAILURE;
809+}
810\ No newline at end of file
811
812=== added file 'spinner/miregl.cpp'
813--- spinner/miregl.cpp 1970-01-01 00:00:00 +0000
814+++ spinner/miregl.cpp 2015-05-28 15:29:59 +0000
815@@ -0,0 +1,198 @@
816+/*
817+ * Copyright © 2015 Canonical Ltd.
818+ *
819+ * This program is free software: you can redistribute it and/or modify
820+ * it under the terms of the GNU General Public License version 3 as
821+ * published by the Free Software Foundation.
822+ *
823+ * This program is distributed in the hope that it will be useful,
824+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
825+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
826+ * GNU General Public License for more details.
827+ *
828+ * You should have received a copy of the GNU General Public License
829+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
830+ */
831+
832+#include "miregl.h"
833+
834+#include <GLES2/gl2.h>
835+
836+class MirEglApp
837+{
838+public:
839+ MirEglApp(MirConnection* const connection, MirPixelFormat pixel_format, EGLint swapinterval);
840+
841+ EGLSurface create_surface(MirSurface* surface);
842+
843+ void release_current();
844+
845+ void make_current(EGLSurface eglsurface) const;
846+
847+ void swap_buffers(EGLSurface eglsurface) const;
848+
849+ void destroy_surface(EGLSurface eglsurface) const;
850+
851+ ~MirEglApp();
852+
853+ MirConnection* const connection;
854+private:
855+ EGLDisplay egldisplay;
856+ EGLContext eglctx;
857+ EGLConfig eglconfig;
858+ EGLint neglconfigs;
859+};
860+
861+std::shared_ptr<MirEglApp> make_mir_eglapp(
862+ MirConnection* const connection, MirPixelFormat const& pixel_format, EGLint swapinterval)
863+{
864+ return std::make_shared<MirEglApp>(connection, pixel_format, swapinterval);
865+}
866+
867+namespace
868+{
869+MirSurface* create_surface(MirConnection* const connection, MirSurfaceParameters const& surfaceparm)
870+{
871+ auto const spec = mir_connection_create_spec_for_normal_surface(
872+ connection,
873+ surfaceparm.width,
874+ surfaceparm.height,
875+ surfaceparm.pixel_format);
876+
877+ mir_surface_spec_set_name(spec, surfaceparm.name);
878+ mir_surface_spec_set_buffer_usage(spec, surfaceparm.buffer_usage);
879+ mir_surface_spec_set_fullscreen_on_output(spec, surfaceparm.output_id);
880+
881+ auto const surface = mir_surface_create_sync(spec);
882+ mir_surface_spec_release(spec);
883+
884+ if (!mir_surface_is_valid(surface))
885+ throw std::runtime_error("Can't create a surface");
886+
887+ if (surfaceparm.output_id != mir_display_output_id_invalid)
888+ mir_surface_set_state(surface, mir_surface_state_fullscreen);
889+
890+ return surface;
891+}
892+}
893+
894+MirEglSurface::MirEglSurface(std::shared_ptr<MirEglApp> const& mir_egl_app, MirSurfaceParameters const& surfaceparm) :
895+ mir_egl_app{mir_egl_app},
896+ surface{create_surface(mir_egl_app->connection, surfaceparm)},
897+ eglsurface{mir_egl_app->create_surface(surface)}
898+{
899+}
900+
901+MirEglSurface::~MirEglSurface()
902+{
903+ mir_egl_app->destroy_surface(eglsurface);
904+ mir_surface_release_sync(surface);
905+}
906+
907+void MirEglSurface::egl_make_current()
908+{
909+ auto const buffer_stream = mir_surface_get_buffer_stream(surface);
910+ mir_buffer_stream_get_current_buffer(buffer_stream, &buffer_package);
911+ mir_egl_app->make_current(eglsurface);
912+}
913+
914+void MirEglSurface::swap_buffers()
915+{
916+ mir_egl_app->swap_buffers(eglsurface);
917+}
918+
919+unsigned int MirEglSurface::width() const
920+{
921+ return buffer_package->width;
922+}
923+
924+unsigned int MirEglSurface::height() const
925+{
926+ return buffer_package->height;
927+}
928+
929+MirEglApp::MirEglApp(MirConnection* const connection, MirPixelFormat pixel_format, EGLint swapinterval) :
930+ connection{connection}
931+{
932+ unsigned int bpp = 8*MIR_BYTES_PER_PIXEL(pixel_format);
933+
934+ EGLint attribs[] =
935+ {
936+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
937+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
938+ EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
939+ EGL_BUFFER_SIZE, (EGLint) bpp,
940+ EGL_NONE
941+ };
942+
943+ egldisplay = eglGetDisplay((EGLNativeDisplayType) mir_connection_get_egl_native_display(connection));
944+ if (egldisplay == EGL_NO_DISPLAY)
945+ throw std::runtime_error("Can't eglGetDisplay");
946+
947+ EGLint major;
948+ EGLint minor;
949+ if (!eglInitialize(egldisplay, &major, &minor))
950+ throw std::runtime_error("Can't eglInitialize");
951+
952+ if (major != 1 || minor != 4)
953+ throw std::runtime_error("EGL version is not 1.4");
954+
955+ if (!eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs))
956+ throw std::runtime_error("Could not eglChooseConfig");
957+
958+ if (neglconfigs == 0)
959+ throw std::runtime_error("No EGL config available");
960+
961+ EGLint ctxattribs[] =
962+ {
963+ EGL_CONTEXT_CLIENT_VERSION, 2,
964+ EGL_NONE
965+ };
966+
967+ eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ctxattribs);
968+ if (eglctx == EGL_NO_CONTEXT)
969+ throw std::runtime_error("eglCreateContext failed");
970+
971+ if (!eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglctx))
972+ throw std::runtime_error("Can't eglMakeCurrent");
973+
974+ eglSwapInterval(egldisplay, swapinterval);
975+}
976+
977+EGLSurface MirEglApp::create_surface(MirSurface* surface)
978+{
979+ auto const eglsurface = eglCreateWindowSurface(
980+ egldisplay,
981+ eglconfig,
982+ (EGLNativeWindowType) mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(surface)), NULL);
983+
984+ if (eglsurface == EGL_NO_SURFACE)
985+ throw std::runtime_error("eglCreateWindowSurface failed");
986+
987+ return eglsurface;
988+}
989+
990+void MirEglApp::make_current(EGLSurface eglsurface) const
991+{
992+ if (!eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx))
993+ throw std::runtime_error("Can't eglMakeCurrent");
994+}
995+
996+void MirEglApp::swap_buffers(EGLSurface eglsurface) const
997+{
998+ eglSwapBuffers(egldisplay, eglsurface);
999+}
1000+
1001+void MirEglApp::destroy_surface(EGLSurface eglsurface) const
1002+{
1003+ eglDestroySurface(egldisplay, eglsurface);
1004+}
1005+
1006+
1007+MirEglApp::~MirEglApp()
1008+{
1009+ eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1010+ eglDestroyContext(egldisplay, eglctx);
1011+ eglTerminate(egldisplay);
1012+ mir_connection_release(connection);
1013+}
1014
1015=== added file 'spinner/miregl.h'
1016--- spinner/miregl.h 1970-01-01 00:00:00 +0000
1017+++ spinner/miregl.h 2015-05-28 15:29:59 +0000
1018@@ -0,0 +1,64 @@
1019+/*
1020+ * Copyright © 2015 Canonical Ltd.
1021+ *
1022+ * This program is free software: you can redistribute it and/or modify
1023+ * it under the terms of the GNU General Public License version 3 as
1024+ * published by the Free Software Foundation.
1025+ *
1026+ * This program is distributed in the hope that it will be useful,
1027+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1028+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1029+ * GNU General Public License for more details.
1030+ *
1031+ * You should have received a copy of the GNU General Public License
1032+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1033+ */
1034+
1035+#ifndef UNITYSYSTEMCOMPOSITOR_MIREGL_H
1036+#define UNITYSYSTEMCOMPOSITOR_MIREGL_H
1037+
1038+#include <mir_toolkit/common.h>
1039+#include <mir_toolkit/client_types.h>
1040+#include "mir_toolkit/mir_client_library.h"
1041+
1042+#include <EGL/egl.h>
1043+
1044+#include <memory>
1045+
1046+class MirEglApp;
1047+class MirEglSurface;
1048+
1049+std::shared_ptr<MirEglApp> make_mir_eglapp(
1050+ MirConnection* const connection,
1051+ MirPixelFormat const& pixel_format,
1052+ EGLint swapinterval);
1053+
1054+class MirEglSurface
1055+{
1056+public:
1057+ MirEglSurface(std::shared_ptr<MirEglApp> const& mir_egl_app, MirSurfaceParameters const& surfaceparm);
1058+
1059+ ~MirEglSurface();
1060+
1061+ template<typename Painter>
1062+ void paint(Painter const& functor)
1063+ {
1064+ egl_make_current();
1065+ functor(width(), height());
1066+ swap_buffers();
1067+ }
1068+
1069+private:
1070+ void egl_make_current();
1071+
1072+ void swap_buffers();
1073+ unsigned int width() const;
1074+ unsigned int height() const;
1075+
1076+ std::shared_ptr<MirEglApp> const mir_egl_app;
1077+ MirSurface* const surface;
1078+ MirBufferPackage* buffer_package;
1079+ EGLSurface const eglsurface;
1080+};
1081+
1082+#endif //UNITYSYSTEMCOMPOSITOR_MIREGL_H
1083
1084=== modified file 'tests/integration-tests/test_dbus_event_loop.cpp'
1085--- tests/integration-tests/test_dbus_event_loop.cpp 2015-03-18 12:48:33 +0000
1086+++ tests/integration-tests/test_dbus_event_loop.cpp 2015-05-28 15:29:59 +0000
1087@@ -201,6 +201,8 @@
1088
1089 static int const timeout_ms = 100;
1090
1091+ auto const start = std::chrono::steady_clock::now();
1092+
1093 dbus_event_loop.enqueue(
1094 [this,&pending_promise]
1095 {
1096@@ -218,7 +220,6 @@
1097 });
1098
1099 // No one is going to reply to the signal, so the notification should time out
1100- auto const start = std::chrono::steady_clock::now();
1101 auto pending = pending_future.get();
1102 auto const end = std::chrono::steady_clock::now();
1103 auto const delay = end - start;

Subscribers

People subscribed via source and target branches