nested-client: Exit if we fail to create the nested client struct
[profile/ivi/weston-ivi-shell.git] / clients / nested-client.c
1 /*
2  * Copyright © 2013 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <wayland-egl.h>
28 #include <wayland-cursor.h>
29
30 #include <GLES2/gl2.h>
31 #include <EGL/egl.h>
32
33 struct window;
34 struct seat;
35
36 struct nested_client {
37         struct wl_display *display;
38         struct wl_registry *registry;
39         struct wl_compositor *compositor;
40
41         EGLDisplay egl_display;
42         EGLContext egl_context;
43         EGLConfig egl_config;
44         EGLSurface egl_surface;
45         struct program *color_program;
46
47         GLuint vert, frag, program;
48         GLuint rotation;
49         GLuint pos;
50         GLuint col;
51
52         struct wl_surface *surface;
53         struct wl_egl_window *native;
54         int width, height;
55 };
56
57 #define POS 0
58 #define COL 1
59
60 static GLuint
61 create_shader(const char *source, GLenum shader_type)
62 {
63         GLuint shader;
64         GLint status;
65
66         shader = glCreateShader(shader_type);
67         if (shader == 0)
68                 return 0;
69
70         glShaderSource(shader, 1, (const char **) &source, NULL);
71         glCompileShader(shader);
72
73         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
74         if (!status) {
75                 char log[1000];
76                 GLsizei len;
77                 glGetShaderInfoLog(shader, 1000, &len, log);
78                 fprintf(stderr, "Error: compiling %s: %*s\n",
79                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
80                         len, log);
81                 return 0;
82         }
83
84         return shader;
85 }
86
87 static void
88 create_program(struct nested_client *client,
89                const char *vert, const char *frag)
90 {
91         GLint status;
92
93         client->vert = create_shader(vert, GL_VERTEX_SHADER);
94         client->frag = create_shader(frag, GL_FRAGMENT_SHADER);
95
96         client->program = glCreateProgram();
97         glAttachShader(client->program, client->frag);
98         glAttachShader(client->program, client->vert);
99         glBindAttribLocation(client->program, POS, "pos");
100         glBindAttribLocation(client->program, COL, "color");
101         glLinkProgram(client->program);
102
103         glGetProgramiv(client->program, GL_LINK_STATUS, &status);
104         if (!status) {
105                 char log[1000];
106                 GLsizei len;
107                 glGetProgramInfoLog(client->program, 1000, &len, log);
108                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
109                 exit(1);
110         }
111
112         client->rotation =
113                 glGetUniformLocation(client->program, "rotation");
114 }
115
116 static const char vertex_shader_text[] =
117         "uniform mat4 rotation;\n"
118         "attribute vec4 pos;\n"
119         "attribute vec4 color;\n"
120         "varying vec4 v_color;\n"
121         "void main() {\n"
122         "  gl_Position = rotation * pos;\n"
123         "  v_color = color;\n"
124         "}\n";
125
126 static const char color_fragment_shader_text[] =
127         "precision mediump float;\n"
128         "varying vec4 v_color;\n"
129         "void main() {\n"
130         "  gl_FragColor = v_color;\n"
131         "}\n";
132
133 static void
134 render_triangle(struct nested_client *client, uint32_t time)
135 {
136         static const GLfloat verts[3][2] = {
137                 { -0.5, -0.5 },
138                 {  0.5, -0.5 },
139                 {  0,    0.5 }
140         };
141         static const GLfloat colors[3][3] = {
142                 { 1, 0, 0 },
143                 { 0, 1, 0 },
144                 { 0, 0, 1 }
145         };
146         GLfloat angle;
147         GLfloat rotation[4][4] = {
148                 { 1, 0, 0, 0 },
149                 { 0, 1, 0, 0 },
150                 { 0, 0, 1, 0 },
151                 { 0, 0, 0, 1 }
152         };
153         static const int32_t speed_div = 5;
154         static uint32_t start_time = 0;
155
156         if (client->program == 0)
157                 create_program(client, vertex_shader_text,
158                                color_fragment_shader_text);
159
160         if (start_time == 0)
161                 start_time = time;
162
163         angle = ((time - start_time) / speed_div) % 360 * M_PI / 180.0;
164         rotation[0][0] =  cos(angle);
165         rotation[0][2] =  sin(angle);
166         rotation[2][0] = -sin(angle);
167         rotation[2][2] =  cos(angle);
168
169         glClearColor(0.4, 0.4, 0.4, 1.0);
170         glClear(GL_COLOR_BUFFER_BIT);
171
172         glUseProgram(client->program);
173
174         glViewport(0, 0, client->width, client->height);
175
176         glUniformMatrix4fv(client->rotation, 1, GL_FALSE,
177                            (GLfloat *) rotation);
178
179         glVertexAttribPointer(POS, 2, GL_FLOAT, GL_FALSE, 0, verts);
180         glVertexAttribPointer(COL, 3, GL_FLOAT, GL_FALSE, 0, colors);
181         glEnableVertexAttribArray(POS);
182         glEnableVertexAttribArray(COL);
183
184         glDrawArrays(GL_TRIANGLES, 0, 3);
185
186         glDisableVertexAttribArray(POS);
187         glDisableVertexAttribArray(COL);
188
189         glFlush();
190 }
191
192 static void
193 frame_callback(void *data, struct wl_callback *callback, uint32_t time);
194
195 static const struct wl_callback_listener frame_listener = {
196         frame_callback
197 };
198
199 static void
200 frame_callback(void *data, struct wl_callback *callback, uint32_t time)
201 {
202         struct nested_client *client = data;
203
204         if (callback)
205                 wl_callback_destroy(callback);
206
207         callback = wl_surface_frame(client->surface);
208         wl_callback_add_listener(callback, &frame_listener, client);
209
210         render_triangle(client, time);
211
212         eglSwapBuffers(client->egl_display, client->egl_surface);
213 }
214
215 static void
216 registry_handle_global(void *data, struct wl_registry *registry,
217                        uint32_t name, const char *interface, uint32_t version)
218 {
219         struct nested_client *client = data;
220
221         if (strcmp(interface, "wl_compositor") == 0) {
222                 client->compositor =
223                         wl_registry_bind(registry, name,
224                                          &wl_compositor_interface, 1);
225         }
226 }
227
228 static void
229 registry_handle_global_remove(void *data, struct wl_registry *registry,
230                               uint32_t name)
231 {
232 }
233
234 static const struct wl_registry_listener registry_listener = {
235         registry_handle_global,
236         registry_handle_global_remove
237 };
238
239 static struct nested_client *
240 nested_client_create(void)
241 {
242         static const EGLint context_attribs[] = {
243                 EGL_CONTEXT_CLIENT_VERSION, 2,
244                 EGL_NONE
245         };
246
247         static const EGLint config_attribs[] = {
248                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
249                 EGL_RED_SIZE, 1,
250                 EGL_GREEN_SIZE, 1,
251                 EGL_BLUE_SIZE, 1,
252                 EGL_ALPHA_SIZE, 1,
253                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
254                 EGL_NONE
255         };
256
257         EGLint major, minor, n;
258         EGLBoolean ret;
259
260         struct nested_client *client;
261
262         client = malloc(sizeof *client);
263         if (client == NULL)
264                 return NULL;
265
266         client->width  = 250;
267         client->height = 250;
268
269         client->display = wl_display_connect(NULL);
270
271         client->registry = wl_display_get_registry(client->display);
272         wl_registry_add_listener(client->registry,
273                                  &registry_listener, client);
274
275         /* get globals */
276         wl_display_roundtrip(client->display);
277
278         client->egl_display = eglGetDisplay(client->display);
279         if (client->egl_display == NULL)
280                 return NULL;
281
282         ret = eglInitialize(client->egl_display, &major, &minor);
283         if (!ret)
284                 return NULL;
285         ret = eglBindAPI(EGL_OPENGL_ES_API);
286         if (!ret)
287                 return NULL;
288
289         ret = eglChooseConfig(client->egl_display, config_attribs,
290                               &client->egl_config, 1, &n);
291         if (!ret || n != 1)
292                 return NULL;
293
294         client->egl_context = eglCreateContext(client->egl_display,
295                                                client->egl_config,
296                                                EGL_NO_CONTEXT,
297                                                context_attribs);
298         if (!client->egl_context)
299                 return NULL;
300
301         client->surface = wl_compositor_create_surface(client->compositor);
302
303         client->native = wl_egl_window_create(client->surface,
304                                               client->width, client->height);
305
306         client->egl_surface =
307                 eglCreateWindowSurface(client->egl_display,
308                                        client->egl_config,
309                                        client->native, NULL);
310
311         eglMakeCurrent(client->egl_display, client->egl_surface,
312                        client->egl_surface, client->egl_context);
313
314         wl_egl_window_resize(client->native,
315                              client->width, client->height, 0, 0);
316
317         frame_callback(client, NULL, 0);
318
319         return client;
320 }
321
322 static void
323 nested_client_destroy(struct nested_client *client)
324 {
325         eglMakeCurrent(client->egl_display,
326                        EGL_NO_SURFACE, EGL_NO_SURFACE,
327                        EGL_NO_CONTEXT);
328
329         wl_egl_window_destroy(client->native);
330
331         wl_surface_destroy(client->surface);
332
333         if (client->compositor)
334                 wl_compositor_destroy(client->compositor);
335
336         wl_registry_destroy(client->registry);
337         wl_display_flush(client->display);
338         wl_display_disconnect(client->display);
339 }
340
341 int
342 main(int argc, char **argv)
343 {
344         struct nested_client *client;
345         int ret = 0;
346
347         if (getenv("WAYLAND_SOCKET") == NULL) {
348                 fprintf(stderr,
349                         "must be run by nested, don't run standalone\n");
350                 return EXIT_FAILURE;
351         }
352
353         client = nested_client_create();
354         if (client == NULL)
355                 return EXIT_FAILURE;
356
357         while (ret != -1)
358                 ret = wl_display_dispatch(client->display);
359
360         nested_client_destroy(client);
361
362         return 0;
363 }