progs/egl: Add an OpenGL ES demo for EGL_OES_image_pixmap.
[mesa.git] / progs / egl / opengles1 / texture_from_pixmap.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 /*
29 * This demo uses EGL_KHR_image_pixmap and GL_OES_EGL_image to demonstrate
30 * texture-from-pixmap.
31 */
32
33 #include <assert.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h> /* for usleep */
38 #include <sys/time.h> /* for gettimeofday */
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/keysym.h>
42 #include <GLES/gl.h>
43 #include <GLES/glext.h>
44 #include <EGL/egl.h>
45 #include <EGL/eglext.h>
46
47 struct app_data {
48 /* native */
49 Display *xdpy;
50 Window canvas, cube;
51 Pixmap pix;
52 unsigned int width, height, depth;
53 GC fg, bg;
54
55 /* EGL */
56 EGLDisplay dpy;
57 EGLContext ctx;
58 EGLSurface surf;
59 EGLImageKHR img;
60
61 /* OpenGL ES */
62 GLuint texture;
63
64 PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
65 PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
66 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
67
68 /* app state */
69 Bool loop;
70 Bool redraw, reshape;
71
72 struct {
73 Bool active;
74 unsigned long next_frame; /* in ms */
75 float view_rotx;
76 float view_roty;
77 float view_rotz;
78
79 } animate;
80
81 struct {
82 Bool active;
83 int x1, y1;
84 int x2, y2;
85 } paint;
86 };
87
88 static void
89 gl_redraw(void)
90 {
91 const GLfloat verts[4][2] = {
92 { -1, -1 },
93 { 1, -1 },
94 { 1, 1 },
95 { -1, 1 }
96 };
97 const GLfloat texcoords[4][2] = {
98 { 0, 1 },
99 { 1, 1 },
100 { 1, 0 },
101 { 0, 0 }
102 };
103 const GLfloat faces[6][4] = {
104 { 0, 0, 1, 0 },
105 { 90, 0, 1, 0 },
106 { 180, 0, 1, 0 },
107 { 270, 0, 1, 0 },
108 { 90, 1, 0, 0 },
109 { -90, 1, 0, 0 }
110 };
111 GLint i;
112
113 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
114
115 glVertexPointer(2, GL_FLOAT, 0, verts);
116 glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
117
118 glEnableClientState(GL_VERTEX_ARRAY);
119 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
120
121 for (i = 0; i < 6; i++) {
122 glPushMatrix();
123 glRotatef(faces[i][0], faces[i][1], faces[i][2], faces[i][3]);
124 glTranslatef(0, 0, 1.0);
125 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
126 glPopMatrix();
127 }
128
129 glDisableClientState(GL_VERTEX_ARRAY);
130 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
131 }
132
133 static void
134 gl_reshape(int width, int height)
135 {
136 GLfloat ar = (GLfloat) width / (GLfloat) height;
137
138 glViewport(0, 0, width, height);
139
140 glMatrixMode(GL_PROJECTION);
141 glLoadIdentity();
142 glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
143
144 glMatrixMode(GL_MODELVIEW);
145 glLoadIdentity();
146 glTranslatef(0.0, 0.0, -10.0);
147 }
148
149 static void
150 app_redraw(struct app_data *data)
151 {
152 /* pixmap has changed */
153 if (data->reshape || data->paint.active) {
154 eglWaitNative(EGL_CORE_NATIVE_ENGINE);
155
156 if (data->reshape) {
157 data->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
158 (GLeglImageOES) data->img);
159 }
160 }
161
162 XCopyArea(data->xdpy, data->pix, data->canvas, data->fg,
163 0, 0, data->width, data->height, 0, 0);
164
165 glPushMatrix();
166 glRotatef(data->animate.view_rotx, 1, 0, 0);
167 glRotatef(data->animate.view_roty, 0, 1, 0);
168 glRotatef(data->animate.view_rotz, 0, 0, 1);
169 gl_redraw();
170 glPopMatrix();
171
172 eglSwapBuffers(data->dpy, data->surf);
173 }
174
175 static void
176 app_reshape(struct app_data *data)
177 {
178 const EGLint img_attribs[] = {
179 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
180 EGL_NONE
181 };
182
183 XResizeWindow(data->xdpy, data->cube, data->width, data->height);
184 XMoveWindow(data->xdpy, data->cube, data->width, 0);
185
186 if (data->img)
187 data->eglDestroyImageKHR(data->dpy, data->img);
188 if (data->pix)
189 XFreePixmap(data->xdpy, data->pix);
190
191 data->pix = XCreatePixmap(data->xdpy, data->canvas, data->width, data->height, data->depth);
192 XFillRectangle(data->xdpy, data->pix, data->bg, 0, 0, data->width, data->height);
193
194 data->img = data->eglCreateImageKHR(data->dpy, EGL_NO_CONTEXT,
195 EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer) data->pix, img_attribs);
196
197 gl_reshape(data->width, data->height);
198 }
199
200 static void
201 app_toggle_animate(struct app_data *data)
202 {
203 data->animate.active = !data->animate.active;
204
205 if (data->animate.active) {
206 struct timeval tv;
207
208 gettimeofday(&tv, NULL);
209 data->animate.next_frame = tv.tv_sec * 1000 + tv.tv_usec / 1000;
210 }
211 }
212
213 static void
214 app_next_event(struct app_data *data)
215 {
216 XEvent event;
217
218 data->reshape = False;
219 data->redraw = False;
220 data->paint.active = False;
221
222 if (data->animate.active) {
223 struct timeval tv;
224 unsigned long now;
225
226 gettimeofday(&tv, NULL);
227 now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
228
229 /* wait for next frame */
230 if (!XPending(data->xdpy) && now < data->animate.next_frame) {
231 usleep((data->animate.next_frame - now) * 1000);
232 gettimeofday(&tv, NULL);
233 now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
234 }
235
236 while (now >= data->animate.next_frame) {
237 data->animate.view_rotx += 1.0;
238 data->animate.view_roty += 2.0;
239 data->animate.view_rotz += 1.5;
240
241 /* 30fps */
242 data->animate.next_frame += 1000 / 30;
243 }
244
245 /* check again in case there were events when sleeping */
246 if (!XPending(data->xdpy)) {
247 data->redraw = True;
248 return;
249 }
250 }
251
252 XNextEvent(data->xdpy, &event);
253
254 switch (event.type) {
255 case ConfigureNotify:
256 data->width = event.xconfigure.width / 2;
257 data->height = event.xconfigure.height;
258 data->reshape = True;
259 break;
260 case Expose:
261 data->redraw = True;
262 break;
263 case KeyPress:
264 {
265 int code;
266
267 code = XLookupKeysym(&event.xkey, 0);
268 switch (code) {
269 case XK_a:
270 app_toggle_animate(data);
271 break;
272 case XK_Escape:
273 data->loop = False;
274 break;
275 default:
276 break;
277 }
278 }
279 break;
280 case ButtonPress:
281 data->paint.x1 = data->paint.x2 = event.xbutton.x;
282 data->paint.y1 = data->paint.y2 = event.xbutton.y;
283 break;
284 case ButtonRelease:
285 data->paint.active = False;
286 break;
287 case MotionNotify:
288 data->paint.x1 = data->paint.x2;
289 data->paint.y1 = data->paint.y2;
290 data->paint.x2 = event.xmotion.x;
291 data->paint.y2 = event.xmotion.y;
292 data->paint.active = True;
293 break;
294 default:
295 break;
296 }
297
298 if (data->paint.active || data->reshape)
299 data->redraw = True;
300 }
301
302 static void
303 app_init_gl(struct app_data *data)
304 {
305 glClearColor(0.1, 0.1, 0.3, 0.0);
306 glColor4f(1.0, 1.0, 1.0, 1.0);
307
308 glGenTextures(1, &data->texture);
309
310 glBindTexture(GL_TEXTURE_2D, data->texture);
311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
313
314 glEnable(GL_TEXTURE_2D);
315 glEnable(GL_DEPTH_TEST);
316 }
317
318 static Bool
319 app_init_exts(struct app_data *data)
320 {
321 const char *exts;
322
323 exts = eglQueryString(data->dpy, EGL_EXTENSIONS);
324 data->eglCreateImageKHR =
325 (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
326 data->eglDestroyImageKHR =
327 (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
328 if (!exts || !strstr(exts, "EGL_KHR_image_pixmap") ||
329 !data->eglCreateImageKHR || !data->eglDestroyImageKHR) {
330 printf("EGL does not support EGL_KHR_image_pixmap\n");
331 return False;
332 }
333
334 exts = (const char *) glGetString(GL_EXTENSIONS);
335 exts = "GL_OES_EGL_image"; /* XXX */
336 data->glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
337 eglGetProcAddress("glEGLImageTargetTexture2DOES");
338 if (!exts || !strstr(exts, "GL_OES_EGL_image") ||
339 !data->glEGLImageTargetTexture2DOES) {
340 printf("OpenGL ES does not support GL_OES_EGL_image\n");
341 return False;
342 }
343
344 return True;
345 }
346
347 static void
348 app_run(struct app_data *data)
349 {
350 Window root;
351 int x, y;
352 unsigned int border;
353
354 if (!eglMakeCurrent(data->dpy, data->surf, data->surf, data->ctx))
355 return;
356
357 if (!app_init_exts(data))
358 return;
359
360 printf("Draw something on the left with the mouse!\n");
361
362 app_init_gl(data);
363
364 if (!XGetGeometry(data->xdpy, data->canvas, &root, &x, &y,
365 &data->width, &data->height, &border, &data->depth))
366 return;
367 data->width /= 2;
368
369 app_reshape(data);
370
371 XMapWindow(data->xdpy, data->canvas);
372 XMapWindow(data->xdpy, data->cube);
373
374 app_toggle_animate(data);
375 data->loop = True;
376
377 while (data->loop) {
378 app_next_event(data);
379
380 if (data->reshape)
381 app_reshape(data);
382 if (data->paint.active) {
383 XDrawLine(data->xdpy, data->pix, data->fg,
384 data->paint.x1, data->paint.y1,
385 data->paint.x2, data->paint.y2);
386 }
387
388 if (data->redraw)
389 app_redraw(data);
390 }
391
392 eglMakeCurrent(data->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
393 }
394
395 static Bool
396 make_x_window(struct app_data *data, const char *name,
397 int x, int y, int width, int height)
398 {
399 static const EGLint attribs[] = {
400 EGL_RED_SIZE, 1,
401 EGL_GREEN_SIZE, 1,
402 EGL_BLUE_SIZE, 1,
403 EGL_DEPTH_SIZE, 1,
404 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
405 EGL_NONE
406 };
407 static const EGLint ctx_attribs[] = {
408 EGL_CONTEXT_CLIENT_VERSION, 1,
409 EGL_NONE
410 };
411 int scrnum;
412 XSetWindowAttributes attr;
413 unsigned long mask;
414 Window root;
415 Window win;
416 XVisualInfo *visInfo, visTemplate;
417 int num_visuals;
418 EGLConfig config;
419 EGLint num_configs;
420 EGLint vid;
421
422 scrnum = DefaultScreen( data->xdpy );
423 root = RootWindow( data->xdpy, scrnum );
424
425 if (!eglChooseConfig( data->dpy, attribs, &config, 1, &num_configs)) {
426 printf("Error: couldn't get an EGL visual config\n");
427 exit(1);
428 }
429
430 assert(config);
431 assert(num_configs > 0);
432
433 if (!eglGetConfigAttrib(data->dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
434 printf("Error: eglGetConfigAttrib() failed\n");
435 exit(1);
436 }
437
438 /* The X window visual must match the EGL config */
439 visTemplate.visualid = vid;
440 visInfo = XGetVisualInfo(data->xdpy, VisualIDMask, &visTemplate, &num_visuals);
441 if (!visInfo) {
442 printf("Error: couldn't get X visual\n");
443 exit(1);
444 }
445
446 /* window attributes */
447 attr.background_pixel = 0;
448 attr.border_pixel = 0;
449 attr.colormap = XCreateColormap( data->xdpy, root, visInfo->visual, AllocNone);
450 attr.event_mask = StructureNotifyMask | ExposureMask |
451 KeyPressMask | ButtonPressMask | ButtonMotionMask;
452 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
453
454 win = XCreateWindow( data->xdpy, root, 0, 0, width * 2, height,
455 0, visInfo->depth, InputOutput,
456 visInfo->visual, mask, &attr );
457
458 /* set hints and properties */
459 {
460 XSizeHints sizehints;
461 sizehints.x = x;
462 sizehints.y = y;
463 sizehints.width = width;
464 sizehints.height = height;
465 sizehints.flags = USSize | USPosition;
466 XSetNormalHints(data->xdpy, win, &sizehints);
467 XSetStandardProperties(data->xdpy, win, name, name,
468 None, (char **)NULL, 0, &sizehints);
469 }
470
471 data->canvas = win;
472
473 attr.event_mask = 0x0;
474 win = XCreateWindow( data->xdpy, win, width, 0, width, height,
475 0, visInfo->depth, InputOutput,
476 visInfo->visual, mask, &attr );
477 data->cube = win;
478
479 eglBindAPI(EGL_OPENGL_ES_API);
480
481 data->ctx = eglCreateContext(data->dpy, config, EGL_NO_CONTEXT, ctx_attribs );
482 if (!data->ctx) {
483 printf("Error: eglCreateContext failed\n");
484 exit(1);
485 }
486
487 data->surf = eglCreateWindowSurface(data->dpy, config, data->cube, NULL);
488 if (!data->surf) {
489 printf("Error: eglCreateWindowSurface failed\n");
490 exit(1);
491 }
492
493 XFree(visInfo);
494
495 return (data->canvas && data->cube && data->ctx && data->surf);
496 }
497
498 static void
499 app_fini(struct app_data *data)
500 {
501 if (data->img)
502 data->eglDestroyImageKHR(data->dpy, data->img);
503 if (data->pix)
504 XFreePixmap(data->xdpy, data->pix);
505
506 if (data->fg)
507 XFreeGC(data->xdpy, data->fg);
508 if (data->bg)
509 XFreeGC(data->xdpy, data->bg);
510
511 if (data->surf)
512 eglDestroySurface(data->dpy, data->surf);
513 if (data->ctx)
514 eglDestroyContext(data->dpy, data->ctx);
515
516 if (data->cube)
517 XDestroyWindow(data->xdpy, data->cube);
518 if (data->canvas)
519 XDestroyWindow(data->xdpy, data->canvas);
520
521 if (data->dpy)
522 eglTerminate(data->dpy);
523 if (data->xdpy)
524 XCloseDisplay(data->xdpy);
525 }
526
527 static Bool
528 app_init(struct app_data *data, int argc, char **argv)
529 {
530 XGCValues gc_vals;
531
532 memset(data, 0, sizeof(*data));
533
534 data->xdpy = XOpenDisplay(NULL);
535 if (!data->xdpy)
536 goto fail;
537
538 data->dpy = eglGetDisplay(data->xdpy);
539 if (!data->dpy || !eglInitialize(data->dpy, NULL, NULL))
540 goto fail;
541
542 if (!make_x_window(data, "EGLImage TFP", 0, 0, 300, 300))
543 goto fail;
544
545 gc_vals.function = GXcopy;
546 gc_vals.foreground = WhitePixel(data->xdpy, DefaultScreen(data->xdpy));
547 gc_vals.line_width = 3;
548 gc_vals.line_style = LineSolid;
549 gc_vals.fill_style = FillSolid;
550
551 data->fg = XCreateGC(data->xdpy, data->canvas,
552 GCFunction | GCForeground | GCLineWidth | GCLineStyle | GCFillStyle,
553 &gc_vals);
554 gc_vals.foreground = BlackPixel(data->xdpy, DefaultScreen(data->xdpy));
555 data->bg = XCreateGC(data->xdpy, data->canvas,
556 GCFunction | GCForeground | GCLineWidth | GCLineStyle | GCFillStyle,
557 &gc_vals);
558 if (!data->fg || !data->bg)
559 goto fail;
560
561 return True;
562
563 fail:
564 app_fini(data);
565 return False;
566 }
567
568 int
569 main(int argc, char **argv)
570 {
571 struct app_data data;
572
573 if (app_init(&data, argc, argv)) {
574 app_run(&data);
575 app_fini(&data);
576 }
577
578 return 0;
579 }