0ae2924ee8455b50c4b76dcc53223de9ca34f179
[profile/ivi/wayland.git] / clients / simple-client.c
1 /*
2  * Copyright © 2011 Benjamin Franzke
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 #include <stddef.h>
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <math.h>
30 #include <assert.h>
31
32 #include <fcntl.h>
33
34 #include <wayland-client.h>
35 #include <xf86drm.h>
36
37 #define GL_GLEXT_PROTOTYPES
38 #define EGL_EGLEXT_PROTOTYPES
39 #include <GLES2/gl2.h>
40 #include <GLES2/gl2ext.h>
41 #include <EGL/egl.h>
42 #include <EGL/eglext.h>
43
44 struct display {
45         struct wl_display *display;
46         struct {
47                 struct wl_compositor *compositor;
48                 struct wl_drm *drm;
49         } interface;
50         struct {
51                 EGLDisplay dpy;
52                 EGLContext ctx;
53         } egl;
54         struct {
55                 int fd;
56                 const char *device_name;
57                 bool authenticated;
58         } drm;
59         uint32_t mask;
60 };
61
62 struct window {
63         struct display *display;
64         struct {
65                 int width, height;
66         } geometry;
67         struct {
68                 GLuint fbo;
69                 GLuint color_rbo;
70
71                 GLuint program;
72                 GLuint rotation_uniform;
73
74                 GLuint pos;
75                 GLuint col;
76         } gl;
77         struct {
78                 struct wl_buffer *buffer;
79                 struct wl_surface *surface;
80                 EGLImageKHR image;
81         } drm_surface;
82 };
83
84 static const char *vert_shader_text =
85         "uniform mat4 rotation;\n"
86         "attribute vec4 pos;\n"
87         "attribute vec4 color;\n"
88         "varying vec4 v_color;\n"
89         "void main() {\n"
90         "  gl_Position = rotation * pos;\n"
91         "  v_color = color;\n"
92         "}\n";
93
94 static const char *frag_shader_text =
95         "precision mediump float;\n"
96         "varying vec4 v_color;\n"
97         "void main() {\n"
98         "  gl_FragColor = v_color;\n"
99         "}\n";
100
101 static void
102 init_egl(struct display *display)
103 {
104         static const EGLint context_attribs[] = {
105                 EGL_CONTEXT_CLIENT_VERSION, 2,
106                 EGL_NONE
107         };
108
109         EGLint major, minor;
110         EGLBoolean ret;
111
112         display->egl.dpy = eglGetDRMDisplayMESA(display->drm.fd);
113         assert(display->egl.dpy);
114
115         ret = eglInitialize(display->egl.dpy, &major, &minor);
116         assert(ret == EGL_TRUE);
117         ret = eglBindAPI(EGL_OPENGL_ES_API);
118         assert(ret == EGL_TRUE);
119
120         display->egl.ctx = eglCreateContext(display->egl.dpy, NULL,
121                                             EGL_NO_CONTEXT, context_attribs);
122         assert(display->egl.ctx);
123         ret = eglMakeCurrent(display->egl.dpy, NULL, NULL, display->egl.ctx);
124         assert(ret == EGL_TRUE);
125 }
126
127 static GLuint
128 create_shader(struct window *window, const char *source, GLenum shader_type)
129 {
130         GLuint shader;
131         GLint status;
132
133         shader = glCreateShader(shader_type);
134         assert(shader != 0);
135
136         glShaderSource(shader, 1, (const char **) &source, NULL);
137         glCompileShader(shader);
138
139         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
140         if (!status) {
141                 char log[1000];
142                 GLsizei len;
143                 glGetShaderInfoLog(shader, 1000, &len, log);
144                 fprintf(stderr, "Error: compiling %s: %*s\n",
145                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
146                         len, log);
147                 exit(1);
148         }
149
150         return shader;
151 }
152
153 static void
154 init_gl(struct window *window)
155 {
156         GLfloat ar;
157         GLuint frag, vert;
158         GLint status;
159
160         glGenFramebuffers(1, &window->gl.fbo);
161         glBindFramebuffer(GL_FRAMEBUFFER, window->gl.fbo);
162
163         glGenRenderbuffers(1, &window->gl.color_rbo);
164
165         glViewport(0, 0, window->geometry.width, window->geometry.height);
166         ar = (GLfloat)window->geometry.width / (GLfloat)window->geometry.height;
167
168         frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
169         vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
170
171         window->gl.program = glCreateProgram();
172         glAttachShader(window->gl.program, frag);
173         glAttachShader(window->gl.program, vert);
174         glLinkProgram(window->gl.program);
175
176         glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status);
177         if (!status) {
178                 char log[1000];
179                 GLsizei len;
180                 glGetProgramInfoLog(window->gl.program, 1000, &len, log);
181                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
182                 exit(1);
183         }
184
185         glUseProgram(window->gl.program);
186         
187         window->gl.pos = 0;
188         window->gl.pos = 1;
189
190         glBindAttribLocation(window->gl.program, window->gl.pos, "pos");
191         glBindAttribLocation(window->gl.program, window->gl.col, "color");
192         glLinkProgram(window->gl.program);
193
194         window->gl.rotation_uniform =
195                 glGetUniformLocation(window->gl.program, "rotation");
196 }
197
198 static void
199 create_surface(struct window *window)
200 {
201         struct display *display = window->display;
202         struct wl_visual *visual;
203         EGLint name, stride;
204         EGLint image_attribs[] = {
205                 EGL_WIDTH,                      0,
206                 EGL_HEIGHT,                     0,
207                 EGL_DRM_BUFFER_FORMAT_MESA,     EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
208                 EGL_DRM_BUFFER_USE_MESA,        EGL_DRM_BUFFER_USE_SCANOUT_MESA,
209                 EGL_NONE
210         };
211
212         window->drm_surface.surface =
213                 wl_compositor_create_surface(display->interface.compositor);
214
215         image_attribs[1] = window->geometry.width;
216         image_attribs[3] = window->geometry.height;
217
218         window->drm_surface.image = eglCreateDRMImageMESA(display->egl.dpy,
219                                                           image_attribs);
220         eglExportDRMImageMESA(display->egl.dpy, window->drm_surface.image,
221                               &name, NULL, &stride);
222         visual = wl_display_get_premultiplied_argb_visual(display->display);
223
224         window->drm_surface.buffer =
225                 wl_drm_create_buffer(display->interface.drm, name,
226                                      window->geometry.width,
227                                      window->geometry.height,
228                                      stride, visual);
229         /* Process wl_drm_create_buffer. */
230         wl_display_iterate(display->display, WL_DISPLAY_WRITABLE);
231
232         wl_surface_attach(window->drm_surface.surface,
233                           window->drm_surface.buffer, 0, 0);
234         wl_surface_map_toplevel(window->drm_surface.surface);
235
236         glBindRenderbuffer(GL_RENDERBUFFER, window->gl.color_rbo);
237         glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
238                                                window->drm_surface.image);
239
240         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
241                                   GL_COLOR_ATTACHMENT0,
242                                   GL_RENDERBUFFER,
243                                   window->gl.color_rbo);
244
245         assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) ==
246                         GL_FRAMEBUFFER_COMPLETE);
247 }
248
249 static void
250 redraw(void *data, uint32_t time)
251 {
252         struct window *window = data;
253         static const GLfloat verts[3][2] = {
254                 { -0.5, -0.5 },
255                 {  0.5, -0.5 },
256                 {  0,    0.5 }
257         };
258         static const GLfloat colors[3][3] = {
259                 { 1, 0, 0 },
260                 { 0, 1, 0 },
261                 { 0, 0, 1 }
262         };
263         GLfloat angle;
264         GLfloat rotation[4][4] = {
265                 { 1, 0, 0, 0 },
266                 { 0, 1, 0, 0 },
267                 { 0, 0, 1, 0 },
268                 { 0, 0, 0, 1 }
269         };
270         static const int32_t speed_div = 5;
271         static uint32_t start_time = 0;
272
273         if (start_time == 0)
274                 start_time = time;
275
276         angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
277         rotation[0][0] =  cos(angle);
278         rotation[0][2] =  sin(angle);
279         rotation[2][0] = -sin(angle);
280         rotation[2][2] =  cos(angle);
281
282         glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
283                            (GLfloat *) rotation);
284
285         glClearColor(0.0, 0.0, 0.0, 0.5);
286         glClear(GL_COLOR_BUFFER_BIT);
287
288         glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
289         glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
290         glEnableVertexAttribArray(window->gl.pos);
291         glEnableVertexAttribArray(window->gl.col);
292
293         glDrawArrays(GL_TRIANGLES, 0, 3);
294
295         glDisableVertexAttribArray(window->gl.pos);
296         glDisableVertexAttribArray(window->gl.col);
297
298         glFlush();
299
300         wl_surface_damage(window->drm_surface.surface, 0, 0,
301                           window->geometry.width, window->geometry.height);
302
303         wl_display_frame_callback(window->display->display, redraw, window);
304 }
305
306 static void
307 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
308 {
309         struct display *d = data;
310
311         d->drm.device_name = strdup(device);
312 }
313
314 static void
315 drm_handle_authenticated(void *data, struct wl_drm *drm)
316 {
317         struct display *d = data;
318
319         d->drm.authenticated = true;
320 }
321
322 static const struct wl_drm_listener drm_listener = {
323         drm_handle_device,
324         drm_handle_authenticated
325 };
326
327 static void
328 display_handle_global(struct wl_display *display, uint32_t id,
329                       const char *interface, uint32_t version, void *data)
330 {
331         struct display *d = data;
332
333         if (strcmp(interface, "compositor") == 0) {
334                 d->interface.compositor = wl_compositor_create(display, id);
335         } else if (strcmp(interface, "drm") == 0) {
336                 d->interface.drm = wl_drm_create(display, id);
337                 wl_drm_add_listener(d->interface.drm, &drm_listener, d);
338         }
339 }
340
341 static int
342 event_mask_update(uint32_t mask, void *data)
343 {
344         struct display *d = data;
345
346         d->mask = mask;
347
348         return 0;
349 }
350
351 int
352 main(int argc, char **argv)
353 {
354         struct display display = { 0 };
355         struct window  window  = { 0 };
356         drm_magic_t magic;
357         int ret;
358
359         memset(&display, 0, sizeof display);
360         memset(&window,  0, sizeof window);
361
362         window.display = &display;
363         window.geometry.width  = 250;
364         window.geometry.height = 250;
365
366         display.display = wl_display_connect(NULL);
367         assert(display.display);
368
369         wl_display_add_global_listener(display.display,
370                                     display_handle_global, &display);
371         /* process connection events */
372         wl_display_iterate(display.display, WL_DISPLAY_READABLE);
373
374         display.drm.fd = open(display.drm.device_name, O_RDWR);
375         assert(display.drm.fd >= 0);
376
377         ret = drmGetMagic(display.drm.fd, &magic);
378         assert(ret == 0);
379         wl_drm_authenticate(display.interface.drm, magic);
380         wl_display_iterate(display.display, WL_DISPLAY_WRITABLE);
381         while (!display.drm.authenticated)
382                 wl_display_iterate(display.display, WL_DISPLAY_READABLE);
383
384         init_egl(&display);
385         init_gl(&window);
386         create_surface(&window);
387
388         wl_display_frame_callback(display.display, redraw, &window);
389
390         wl_display_get_fd(display.display, event_mask_update, &display);
391         while (true)
392                 wl_display_iterate(display.display, display.mask);
393         
394         return 0;
395 }