simple-client: Remove unnecessary flush
[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
230         wl_surface_attach(window->drm_surface.surface,
231                           window->drm_surface.buffer, 0, 0);
232         wl_surface_map_toplevel(window->drm_surface.surface);
233
234         glBindRenderbuffer(GL_RENDERBUFFER, window->gl.color_rbo);
235         glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
236                                                window->drm_surface.image);
237
238         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
239                                   GL_COLOR_ATTACHMENT0,
240                                   GL_RENDERBUFFER,
241                                   window->gl.color_rbo);
242
243         assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) ==
244                         GL_FRAMEBUFFER_COMPLETE);
245 }
246
247 static void
248 redraw(void *data, uint32_t time)
249 {
250         struct window *window = data;
251         static const GLfloat verts[3][2] = {
252                 { -0.5, -0.5 },
253                 {  0.5, -0.5 },
254                 {  0,    0.5 }
255         };
256         static const GLfloat colors[3][3] = {
257                 { 1, 0, 0 },
258                 { 0, 1, 0 },
259                 { 0, 0, 1 }
260         };
261         GLfloat angle;
262         GLfloat rotation[4][4] = {
263                 { 1, 0, 0, 0 },
264                 { 0, 1, 0, 0 },
265                 { 0, 0, 1, 0 },
266                 { 0, 0, 0, 1 }
267         };
268         static const int32_t speed_div = 5;
269         static uint32_t start_time = 0;
270
271         if (start_time == 0)
272                 start_time = time;
273
274         angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
275         rotation[0][0] =  cos(angle);
276         rotation[0][2] =  sin(angle);
277         rotation[2][0] = -sin(angle);
278         rotation[2][2] =  cos(angle);
279
280         glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
281                            (GLfloat *) rotation);
282
283         glClearColor(0.0, 0.0, 0.0, 0.5);
284         glClear(GL_COLOR_BUFFER_BIT);
285
286         glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
287         glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
288         glEnableVertexAttribArray(window->gl.pos);
289         glEnableVertexAttribArray(window->gl.col);
290
291         glDrawArrays(GL_TRIANGLES, 0, 3);
292
293         glDisableVertexAttribArray(window->gl.pos);
294         glDisableVertexAttribArray(window->gl.col);
295
296         glFlush();
297
298         wl_surface_damage(window->drm_surface.surface, 0, 0,
299                           window->geometry.width, window->geometry.height);
300
301         wl_display_frame_callback(window->display->display, redraw, window);
302 }
303
304 static void
305 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
306 {
307         struct display *d = data;
308
309         d->drm.device_name = strdup(device);
310 }
311
312 static void
313 drm_handle_authenticated(void *data, struct wl_drm *drm)
314 {
315         struct display *d = data;
316
317         d->drm.authenticated = true;
318 }
319
320 static const struct wl_drm_listener drm_listener = {
321         drm_handle_device,
322         drm_handle_authenticated
323 };
324
325 static void
326 display_handle_global(struct wl_display *display, uint32_t id,
327                       const char *interface, uint32_t version, void *data)
328 {
329         struct display *d = data;
330
331         if (strcmp(interface, "compositor") == 0) {
332                 d->interface.compositor = wl_compositor_create(display, id);
333         } else if (strcmp(interface, "drm") == 0) {
334                 d->interface.drm = wl_drm_create(display, id);
335                 wl_drm_add_listener(d->interface.drm, &drm_listener, d);
336         }
337 }
338
339 static int
340 event_mask_update(uint32_t mask, void *data)
341 {
342         struct display *d = data;
343
344         d->mask = mask;
345
346         return 0;
347 }
348
349 int
350 main(int argc, char **argv)
351 {
352         struct display display = { 0 };
353         struct window  window  = { 0 };
354         drm_magic_t magic;
355         int ret;
356
357         memset(&display, 0, sizeof display);
358         memset(&window,  0, sizeof window);
359
360         window.display = &display;
361         window.geometry.width  = 250;
362         window.geometry.height = 250;
363
364         display.display = wl_display_connect(NULL);
365         assert(display.display);
366
367         wl_display_add_global_listener(display.display,
368                                     display_handle_global, &display);
369         /* process connection events */
370         wl_display_iterate(display.display, WL_DISPLAY_READABLE);
371
372         display.drm.fd = open(display.drm.device_name, O_RDWR);
373         assert(display.drm.fd >= 0);
374
375         ret = drmGetMagic(display.drm.fd, &magic);
376         assert(ret == 0);
377         wl_drm_authenticate(display.interface.drm, magic);
378         wl_display_iterate(display.display, WL_DISPLAY_WRITABLE);
379         while (!display.drm.authenticated)
380                 wl_display_iterate(display.display, WL_DISPLAY_READABLE);
381
382         init_egl(&display);
383         init_gl(&window);
384         create_surface(&window);
385
386         wl_display_frame_callback(display.display, redraw, &window);
387
388         wl_display_get_fd(display.display, event_mask_update, &display);
389         while (true)
390                 wl_display_iterate(display.display, display.mask);
391         
392         return 0;
393 }