blob: 1161a992f00283ee980148033bb86403b68ab414 [file] [log] [blame]
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001/*
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
33struct window;
34struct seat;
35
36struct 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
60static GLuint
61create_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
87static void
88create_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
116static 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
126static 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
133static void
134render_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
192static void
193frame_callback(void *data, struct wl_callback *callback, uint32_t time);
194
195static const struct wl_callback_listener frame_listener = {
196 frame_callback
197};
198
199static void
200frame_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
215static void
216registry_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
228static void
229registry_handle_global_remove(void *data, struct wl_registry *registry,
230 uint32_t name)
231{
232}
233
234static const struct wl_registry_listener registry_listener = {
235 registry_handle_global,
236 registry_handle_global_remove
237};
238
239static struct nested_client *
240nested_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
322static void
323nested_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
341int
342main(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");
Kristian Høgsbergf1144dd2013-10-09 13:25:58 -0700350 return EXIT_FAILURE;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400351 }
352
353 client = nested_client_create();
Kristian Høgsbergf1144dd2013-10-09 13:25:58 -0700354 if (client == NULL)
355 return EXIT_FAILURE;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400356
357 while (ret != -1)
358 ret = wl_display_dispatch(client->display);
359
360 nested_client_destroy(client);
361
362 return 0;
363}