blob: 9893a82f7eb6489f5d3c78d66445734fed90cfbd [file] [log] [blame]
Benjamin Franzkeaabdce02011-01-15 00:40:17 +01001/*
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>
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010026#include <stdbool.h>
27#include <math.h>
28#include <assert.h>
Pekka Paalanen88e60fc2011-12-13 12:09:09 +020029#include <signal.h>
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010030
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010031#include <wayland-client.h>
Kristian Høgsberga495a5e2011-02-04 15:31:33 -050032#include <wayland-egl.h>
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010033
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010034#include <GLES2/gl2.h>
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010035#include <EGL/egl.h>
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010036
37struct display {
38 struct wl_display *display;
Kristian Høgsberga495a5e2011-02-04 15:31:33 -050039 struct wl_compositor *compositor;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -040040 struct wl_shell *shell;
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010041 struct {
42 EGLDisplay dpy;
43 EGLContext ctx;
Kristian Høgsberga495a5e2011-02-04 15:31:33 -050044 EGLConfig conf;
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010045 } egl;
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010046 uint32_t mask;
47};
48
49struct window {
50 struct display *display;
51 struct {
52 int width, height;
53 } geometry;
54 struct {
55 GLuint fbo;
56 GLuint color_rbo;
57
58 GLuint program;
59 GLuint rotation_uniform;
60
61 GLuint pos;
62 GLuint col;
63 } gl;
Kristian Høgsberga495a5e2011-02-04 15:31:33 -050064
65 struct wl_egl_window *native;
66 struct wl_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020067 struct wl_shell_surface *shell_surface;
Kristian Høgsberga495a5e2011-02-04 15:31:33 -050068 EGLSurface egl_surface;
Pekka Paalanen2c2c1062011-12-13 14:50:25 +020069 struct wl_callback *callback;
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010070};
71
72static const char *vert_shader_text =
73 "uniform mat4 rotation;\n"
74 "attribute vec4 pos;\n"
75 "attribute vec4 color;\n"
76 "varying vec4 v_color;\n"
77 "void main() {\n"
78 " gl_Position = rotation * pos;\n"
79 " v_color = color;\n"
80 "}\n";
81
82static const char *frag_shader_text =
Kristian Høgsberg1a11fac2011-01-14 20:39:21 -050083 "precision mediump float;\n"
Benjamin Franzkeaabdce02011-01-15 00:40:17 +010084 "varying vec4 v_color;\n"
85 "void main() {\n"
86 " gl_FragColor = v_color;\n"
87 "}\n";
88
89static void
90init_egl(struct display *display)
91{
Kristian Høgsberg1a11fac2011-01-14 20:39:21 -050092 static const EGLint context_attribs[] = {
93 EGL_CONTEXT_CLIENT_VERSION, 2,
94 EGL_NONE
95 };
96
Kristian Høgsberga495a5e2011-02-04 15:31:33 -050097 static const EGLint config_attribs[] = {
Kristian Høgsberg8e81df42012-01-11 14:24:46 -050098 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
Kristian Høgsberga495a5e2011-02-04 15:31:33 -050099 EGL_RED_SIZE, 1,
100 EGL_GREEN_SIZE, 1,
101 EGL_BLUE_SIZE, 1,
Benjamin Franzke2eae9e32011-03-17 15:43:21 +0100102 EGL_ALPHA_SIZE, 1,
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500103 EGL_DEPTH_SIZE, 1,
104 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
105 EGL_NONE
106 };
107
108 EGLint major, minor, n;
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100109 EGLBoolean ret;
110
Kristian Høgsberg91342c62011-04-14 14:44:58 -0400111 display->egl.dpy = eglGetDisplay(display->display);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100112 assert(display->egl.dpy);
113
114 ret = eglInitialize(display->egl.dpy, &major, &minor);
115 assert(ret == EGL_TRUE);
Kristian Høgsberg1a11fac2011-01-14 20:39:21 -0500116 ret = eglBindAPI(EGL_OPENGL_ES_API);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100117 assert(ret == EGL_TRUE);
118
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500119 assert(eglChooseConfig(display->egl.dpy, config_attribs,
120 &display->egl.conf, 1, &n) && n == 1);
121
122 display->egl.ctx = eglCreateContext(display->egl.dpy,
123 display->egl.conf,
Kristian Høgsberg1a11fac2011-01-14 20:39:21 -0500124 EGL_NO_CONTEXT, context_attribs);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100125 assert(display->egl.ctx);
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500126
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100127}
128
Pekka Paalanen2c2c1062011-12-13 14:50:25 +0200129static void
130fini_egl(struct display *display)
131{
132 /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
133 * on eglReleaseThread(). */
134 eglMakeCurrent(display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
135 EGL_NO_CONTEXT);
136
137 eglTerminate(display->egl.dpy);
138 eglReleaseThread();
139}
140
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100141static GLuint
142create_shader(struct window *window, const char *source, GLenum shader_type)
143{
144 GLuint shader;
145 GLint status;
146
147 shader = glCreateShader(shader_type);
148 assert(shader != 0);
149
150 glShaderSource(shader, 1, (const char **) &source, NULL);
151 glCompileShader(shader);
152
153 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
154 if (!status) {
155 char log[1000];
156 GLsizei len;
157 glGetShaderInfoLog(shader, 1000, &len, log);
158 fprintf(stderr, "Error: compiling %s: %*s\n",
159 shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
160 len, log);
161 exit(1);
162 }
163
164 return shader;
165}
166
167static void
168init_gl(struct window *window)
169{
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100170 GLuint frag, vert;
171 GLint status;
172
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100173 glViewport(0, 0, window->geometry.width, window->geometry.height);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100174
175 frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
176 vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
177
178 window->gl.program = glCreateProgram();
179 glAttachShader(window->gl.program, frag);
180 glAttachShader(window->gl.program, vert);
181 glLinkProgram(window->gl.program);
182
183 glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status);
184 if (!status) {
185 char log[1000];
186 GLsizei len;
187 glGetProgramInfoLog(window->gl.program, 1000, &len, log);
188 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
189 exit(1);
190 }
191
192 glUseProgram(window->gl.program);
193
194 window->gl.pos = 0;
195 window->gl.pos = 1;
196
197 glBindAttribLocation(window->gl.program, window->gl.pos, "pos");
198 glBindAttribLocation(window->gl.program, window->gl.col, "color");
199 glLinkProgram(window->gl.program);
200
201 window->gl.rotation_uniform =
202 glGetUniformLocation(window->gl.program, "rotation");
203}
204
205static void
206create_surface(struct window *window)
207{
208 struct display *display = window->display;
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500209 EGLBoolean ret;
Benjamin Franzke65e50512011-05-31 11:36:31 +0200210
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500211 window->surface = wl_compositor_create_surface(display->compositor);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200212 window->shell_surface = wl_shell_get_shell_surface(display->shell,
213 window->surface);
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500214 window->native =
Kristian Høgsberg91342c62011-04-14 14:44:58 -0400215 wl_egl_window_create(window->surface,
Kristian Høgsbergbfb8e612011-02-07 10:30:38 -0500216 window->geometry.width,
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400217 window->geometry.height);
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500218 window->egl_surface =
219 eglCreateWindowSurface(display->egl.dpy,
220 display->egl.conf,
Kristian Høgsberg8e81df42012-01-11 14:24:46 -0500221 window->native, NULL);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100222
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200223 wl_shell_surface_set_toplevel(window->shell_surface);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100224
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500225 ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
226 window->egl_surface, window->display->egl.ctx);
227 assert(ret == EGL_TRUE);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100228}
229
Pekka Paalanen2c2c1062011-12-13 14:50:25 +0200230static void
231destroy_surface(struct window *window)
232{
233 wl_egl_window_destroy(window->native);
234
235 wl_shell_surface_destroy(window->shell_surface);
236 wl_surface_destroy(window->surface);
237
238 if (window->callback)
239 wl_callback_destroy(window->callback);
240}
241
Kristian Høgsberg33418202011-08-16 23:01:28 -0400242static const struct wl_callback_listener frame_listener;
243
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100244static void
Kristian Høgsberg33418202011-08-16 23:01:28 -0400245redraw(void *data, struct wl_callback *callback, uint32_t time)
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100246{
247 struct window *window = data;
248 static const GLfloat verts[3][2] = {
249 { -0.5, -0.5 },
250 { 0.5, -0.5 },
251 { 0, 0.5 }
252 };
253 static const GLfloat colors[3][3] = {
254 { 1, 0, 0 },
255 { 0, 1, 0 },
256 { 0, 0, 1 }
257 };
258 GLfloat angle;
259 GLfloat rotation[4][4] = {
260 { 1, 0, 0, 0 },
261 { 0, 1, 0, 0 },
262 { 0, 0, 1, 0 },
263 { 0, 0, 0, 1 }
264 };
265 static const int32_t speed_div = 5;
266 static uint32_t start_time = 0;
267
268 if (start_time == 0)
269 start_time = time;
270
271 angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
272 rotation[0][0] = cos(angle);
273 rotation[0][2] = sin(angle);
274 rotation[2][0] = -sin(angle);
275 rotation[2][2] = cos(angle);
276
277 glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
278 (GLfloat *) rotation);
279
280 glClearColor(0.0, 0.0, 0.0, 0.5);
281 glClear(GL_COLOR_BUFFER_BIT);
282
283 glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
284 glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
285 glEnableVertexAttribArray(window->gl.pos);
286 glEnableVertexAttribArray(window->gl.col);
287
288 glDrawArrays(GL_TRIANGLES, 0, 3);
289
290 glDisableVertexAttribArray(window->gl.pos);
291 glDisableVertexAttribArray(window->gl.col);
292
293 glFlush();
294
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500295 eglSwapBuffers(window->display->egl.dpy, window->egl_surface);
Kristian Høgsberg33418202011-08-16 23:01:28 -0400296 if (callback)
297 wl_callback_destroy(callback);
298
Pekka Paalanen2c2c1062011-12-13 14:50:25 +0200299 window->callback = wl_surface_frame(window->surface);
300 wl_callback_add_listener(window->callback, &frame_listener, window);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100301}
302
Kristian Høgsberg33418202011-08-16 23:01:28 -0400303static const struct wl_callback_listener frame_listener = {
304 redraw
305};
306
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100307static void
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100308display_handle_global(struct wl_display *display, uint32_t id,
309 const char *interface, uint32_t version, void *data)
310{
311 struct display *d = data;
312
Kristian Høgsberg8357cd62011-05-13 13:24:56 -0400313 if (strcmp(interface, "wl_compositor") == 0) {
Kristian Høgsbergf790c792011-08-19 14:41:57 -0400314 d->compositor =
315 wl_display_bind(display, id, &wl_compositor_interface);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400316 } else if (strcmp(interface, "wl_shell") == 0) {
Kristian Høgsbergf790c792011-08-19 14:41:57 -0400317 d->shell = wl_display_bind(display, id, &wl_shell_interface);
Kristian Høgsberg8357cd62011-05-13 13:24:56 -0400318 }
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100319}
320
321static int
322event_mask_update(uint32_t mask, void *data)
323{
324 struct display *d = data;
325
326 d->mask = mask;
327
328 return 0;
329}
330
Pekka Paalanen88e60fc2011-12-13 12:09:09 +0200331static int running = 1;
332
333static void
334signal_int(int signum)
335{
336 running = 0;
337}
338
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100339int
340main(int argc, char **argv)
341{
Pekka Paalanen88e60fc2011-12-13 12:09:09 +0200342 struct sigaction sigint;
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100343 struct display display = { 0 };
344 struct window window = { 0 };
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100345
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100346 window.display = &display;
347 window.geometry.width = 250;
348 window.geometry.height = 250;
349
350 display.display = wl_display_connect(NULL);
351 assert(display.display);
352
353 wl_display_add_global_listener(display.display,
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500354 display_handle_global, &display);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100355
Benjamin Franzke65e50512011-05-31 11:36:31 +0200356 wl_display_get_fd(display.display, event_mask_update, &display);
Kristian Høgsberg33418202011-08-16 23:01:28 -0400357 wl_display_iterate(display.display, WL_DISPLAY_READABLE);
Benjamin Franzke65e50512011-05-31 11:36:31 +0200358
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100359 init_egl(&display);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100360 create_surface(&window);
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500361 init_gl(&window);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100362
Pekka Paalanen88e60fc2011-12-13 12:09:09 +0200363 sigint.sa_handler = signal_int;
364 sigemptyset(&sigint.sa_mask);
365 sigint.sa_flags = SA_RESETHAND;
366 sigaction(SIGINT, &sigint, NULL);
367
Kristian Høgsberg33418202011-08-16 23:01:28 -0400368 redraw(&window, NULL, 0);
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100369
Pekka Paalanen88e60fc2011-12-13 12:09:09 +0200370 while (running)
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100371 wl_display_iterate(display.display, display.mask);
Kristian Høgsberga495a5e2011-02-04 15:31:33 -0500372
Pekka Paalanen88e60fc2011-12-13 12:09:09 +0200373 fprintf(stderr, "simple-egl exiting\n");
374
Pekka Paalanen2c2c1062011-12-13 14:50:25 +0200375 destroy_surface(&window);
376 fini_egl(&display);
377
378 if (display.shell)
379 wl_shell_destroy(display.shell);
380
381 if (display.compositor)
382 wl_compositor_destroy(display.compositor);
383
Pekka Paalanenfb850c42011-12-15 10:07:52 +0200384 wl_display_flush(display.display);
Kristian Høgsbergfcfc83f2012-02-28 14:29:19 -0500385 wl_display_disconnect(display.display);
Pekka Paalanen2c2c1062011-12-13 14:50:25 +0200386
Benjamin Franzkeaabdce02011-01-15 00:40:17 +0100387 return 0;
388}