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