~unity-system-compositor-team/unity-system-compositor/trunk

« back to all changes in this revision

Viewing changes to spinner/eglapp.c

  • Committer: CI bot
  • Author(s): Michael Terry, Mirco Müller
  • Date: 2014-05-29 14:38:31 UTC
  • mfrom: (115.5.35 new-gl-screen)
  • Revision ID: ps-jenkins@lists.canonical.com-20140529143831-q29e2sm9im8852mu
This branch adds a new option "--spinner=/path" which allows for an interstitial 'busy wait' program to be specified during boot and between greeter and user sessions. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2013 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
 
17
 */
 
18
 
 
19
#include "eglapp.h"
 
20
#include "mir_toolkit/mir_client_library.h"
 
21
#include <stdio.h>
 
22
#include <stdlib.h>
 
23
#include <signal.h>
 
24
#include <time.h>
 
25
#include <EGL/egl.h>
 
26
#include <GLES2/gl2.h>
 
27
 
 
28
float mir_eglapp_background_opacity = 1.0f;
 
29
 
 
30
static const char appname[] = "eglspinner";
 
31
 
 
32
static MirConnection *connection;
 
33
static MirSurface *surface;
 
34
static EGLDisplay egldisplay;
 
35
static EGLSurface eglsurface;
 
36
static volatile sig_atomic_t running = 0;
 
37
 
 
38
#define CHECK(_cond, _err) \
 
39
    if (!(_cond)) \
 
40
    { \
 
41
        printf("%s\n", (_err)); \
 
42
        return 0; \
 
43
    }
 
44
 
 
45
void mir_eglapp_shutdown(void)
 
46
{
 
47
    eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 
48
    eglTerminate(egldisplay);
 
49
    mir_surface_release_sync(surface);
 
50
    surface = NULL;
 
51
    mir_connection_release(connection);
 
52
    connection = NULL;
 
53
}
 
54
 
 
55
static void shutdown(int signum)
 
56
{
 
57
    if (running)
 
58
    {
 
59
        running = 0;
 
60
        printf("Signal %d received. Good night.\n", signum);
 
61
    }
 
62
}
 
63
 
 
64
mir_eglapp_bool mir_eglapp_running(void)
 
65
{
 
66
    return running;
 
67
}
 
68
 
 
69
void mir_eglapp_swap_buffers(void)
 
70
{
 
71
    EGLint width, height;
 
72
 
 
73
    if (!running)
 
74
        return;
 
75
 
 
76
    eglSwapBuffers(egldisplay, eglsurface);
 
77
 
 
78
    /*
 
79
     * Querying the surface (actually the current buffer) dimensions here is
 
80
     * the only truly safe way to be sure that the dimensions we think we
 
81
     * have are those of the buffer being rendered to. But this should be
 
82
     * improved in future; https://bugs.launchpad.net/mir/+bug/1194384
 
83
     */
 
84
    if (eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width) &&
 
85
        eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height))
 
86
    {
 
87
        glViewport(0, 0, width, height);
 
88
    }
 
89
}
 
90
 
 
91
static void mir_eglapp_handle_event(MirSurface* surface, MirEvent const* ev, void* context)
 
92
{
 
93
    (void) surface;
 
94
    (void) context;
 
95
    if (ev->type == mir_event_type_resize)
 
96
    {
 
97
        /*
 
98
         * FIXME: https://bugs.launchpad.net/mir/+bug/1194384
 
99
         * It is unsafe to set the width and height here because we're in a
 
100
         * different thread to that doing the rendering. So we either need
 
101
         * support for event queuing (directing them to another thread) or
 
102
         * full single-threaded callbacks. (LP: #1194384).
 
103
         */
 
104
        printf("Resized to %dx%d\n", ev->resize.width, ev->resize.height);
 
105
    }
 
106
}
 
107
 
 
108
static const MirDisplayOutput *find_active_output(
 
109
    const MirDisplayConfiguration *conf)
 
110
{
 
111
    const MirDisplayOutput *output = NULL;
 
112
    int d;
 
113
 
 
114
    for (d = 0; d < (int)conf->num_outputs; d++)
 
115
    {
 
116
        const MirDisplayOutput *out = conf->outputs + d;
 
117
 
 
118
        if (out->used &&
 
119
            out->connected &&
 
120
            out->num_modes &&
 
121
            out->current_mode < out->num_modes)
 
122
        {
 
123
            output = out;
 
124
            break;
 
125
        }
 
126
    }
 
127
 
 
128
    return output;
 
129
}
 
130
 
 
131
mir_eglapp_bool mir_eglapp_init(int argc, char *argv[],
 
132
                                unsigned int *width, unsigned int *height)
 
133
{
 
134
    EGLint ctxattribs[] =
 
135
    {
 
136
        EGL_CONTEXT_CLIENT_VERSION, 2,
 
137
        EGL_NONE
 
138
    };
 
139
    MirSurfaceParameters surfaceparm =
 
140
    {
 
141
        "eglappsurface",
 
142
        256, 256,
 
143
        mir_pixel_format_xbgr_8888,
 
144
        mir_buffer_usage_hardware,
 
145
        mir_display_output_id_invalid
 
146
    };
 
147
    MirEventDelegate delegate = 
 
148
    {
 
149
        mir_eglapp_handle_event,
 
150
        NULL
 
151
    };
 
152
    EGLConfig eglconfig;
 
153
    EGLint neglconfigs;
 
154
    EGLContext eglctx;
 
155
    EGLBoolean ok;
 
156
    EGLint swapinterval = 1;
 
157
    char *mir_socket = NULL;
 
158
 
 
159
    if (argc > 1)
 
160
    {
 
161
        int i;
 
162
        for (i = 1; i < argc; i++)
 
163
        {
 
164
            mir_eglapp_bool help = 0;
 
165
            const char *arg = argv[i];
 
166
 
 
167
            if (arg[0] == '-')
 
168
            {
 
169
                switch (arg[1])
 
170
                {
 
171
                case 'b':
 
172
                    {
 
173
                        float alpha = 1.0f;
 
174
                        arg += 2;
 
175
                        if (!arg[0] && i < argc-1)
 
176
                        {
 
177
                            i++;
 
178
                            arg = argv[i];
 
179
                        }
 
180
                        if (sscanf(arg, "%f", &alpha) == 1)
 
181
                        {
 
182
                            mir_eglapp_background_opacity = alpha;
 
183
                        }
 
184
                        else
 
185
                        {
 
186
                            printf("Invalid opacity value: %s\n", arg);
 
187
                            help = 1;
 
188
                        }
 
189
                    }
 
190
                    break;
 
191
                case 'n':
 
192
                    swapinterval = 0;
 
193
                    break;
 
194
                case 'o':
 
195
                    {
 
196
                        unsigned int output_id = 0;
 
197
                        arg += 2;
 
198
                        if (!arg[0] && i < argc-1)
 
199
                        {
 
200
                            i++;
 
201
                            arg = argv[i];
 
202
                        }
 
203
                        if (sscanf(arg, "%u", &output_id) == 1)
 
204
                        {
 
205
                            surfaceparm.output_id = output_id;
 
206
                        }
 
207
                        else
 
208
                        {
 
209
                            printf("Invalid output ID: %s\n", arg);
 
210
                            help = 1;
 
211
                        }
 
212
                    }
 
213
                    break;
 
214
                case 'f':
 
215
                    *width = 0;
 
216
                    *height = 0;
 
217
                    break;
 
218
                case 's':
 
219
                    {
 
220
                        unsigned int w, h;
 
221
                        arg += 2;
 
222
                        if (!arg[0] && i < argc-1)
 
223
                        {
 
224
                            i++;
 
225
                            arg = argv[i];
 
226
                        }
 
227
                        if (sscanf(arg, "%ux%u", &w, &h) == 2)
 
228
                        {
 
229
                            *width = w;
 
230
                            *height = h;
 
231
                        }
 
232
                        else
 
233
                        {
 
234
                            printf("Invalid size: %s\n", arg);
 
235
                            help = 1;
 
236
                        }
 
237
                    }
 
238
                    break;
 
239
                case 'm':
 
240
                    mir_socket = argv[++i];
 
241
                    break;
 
242
                case 'q':
 
243
                    {
 
244
                        FILE *unused = freopen("/dev/null", "a", stdout);
 
245
                        (void)unused;
 
246
                        break;
 
247
                    }
 
248
                case 'h':
 
249
                default:
 
250
                    help = 1;
 
251
                    break;
 
252
                }
 
253
            }
 
254
            else
 
255
            {
 
256
                help = 1;
 
257
            }
 
258
 
 
259
            if (help)
 
260
            {
 
261
                printf("Usage: %s [<options>]\n"
 
262
                       "  -b               Background opacity (0.0 - 1.0)\n"
 
263
                       "  -h               Show this help text\n"
 
264
                       "  -f               Force full screen\n"
 
265
                       "  -o ID            Force placement on output monitor ID\n"
 
266
                       "  -n               Don't sync to vblank\n"
 
267
                       "  -m socket        Mir server socket\n"
 
268
                       "  -s WIDTHxHEIGHT  Force surface size\n"
 
269
                       "  -q               Quiet mode (no messages output)\n"
 
270
                       , argv[0]);
 
271
                return 0;
 
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, &delegate);
 
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_surface_get_egl_native_window(surface),
 
341
            NULL);
 
342
    CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed");
 
343
 
 
344
    eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT,
 
345
                              ctxattribs);
 
346
    CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed");
 
347
 
 
348
    ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx);
 
349
    CHECK(ok, "Can't eglMakeCurrent");
 
350
 
 
351
    signal(SIGINT, shutdown);
 
352
    signal(SIGTERM, shutdown);
 
353
 
 
354
    *width = surfaceparm.width;
 
355
    *height = surfaceparm.height;
 
356
 
 
357
    eglSwapInterval(egldisplay, swapinterval);
 
358
 
 
359
    running = 1;
 
360
 
 
361
    return 1;
 
362
}
 
363
 
 
364
struct MirConnection* mir_eglapp_native_connection()
 
365
{
 
366
    return connection;
 
367
}
 
368
 
 
369
struct MirSurface* mir_eglapp_native_surface()
 
370
{
 
371
    return surface;
 
372
}