summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChia-I Wu <olvaffe@gmail.com>2011-06-27 15:20:40 +0900
committerChia-I Wu <olvaffe@gmail.com>2011-06-28 15:09:31 +0900
commita05e5db67134086e4f2fc8480890a2b315c8c704 (patch)
tree002038d4ae0bdbdcdb1448f1a9b8b0b8f2f7f7aa
parent0e83890b5eae0236537d844c60375072210995d9 (diff)
eglfbdev: add a demo for EGL on fbdev
-rw-r--r--src/egl/opengles1/Makefile.am1
-rw-r--r--src/egl/opengles1/eglfbdev.c338
2 files changed, 339 insertions, 0 deletions
diff --git a/src/egl/opengles1/Makefile.am b/src/egl/opengles1/Makefile.am
index 752c3d1d..7a9828d3 100644
--- a/src/egl/opengles1/Makefile.am
+++ b/src/egl/opengles1/Makefile.am
@@ -43,6 +43,7 @@ noinst_PROGRAMS = \
clear \
drawtex_screen \
drawtex_x11 \
+ eglfbdev \
es1_info \
gears_screen \
gears_x11 \
diff --git a/src/egl/opengles1/eglfbdev.c b/src/egl/opengles1/eglfbdev.c
new file mode 100644
index 00000000..bbc268e7
--- /dev/null
+++ b/src/egl/opengles1/eglfbdev.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2011 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+/*
+ * This is a demonstration of EGL on fbdev:
+ *
+ * The native display is the fd of the device;
+ * There is only one native window, NULL;
+ * There is no native pixmaps.
+ *
+ * It is the app's responsibility to set up the tty, open the fb device, and
+ * initialize EGL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+/* for tty */
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <signal.h>
+
+/* for fbdev */
+#include <linux/fb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* for EGL */
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+static int tty_fd = -1;
+static int tty_saved_vtno;
+
+static int tty_open_vt(int vtno)
+{
+ const char tty[] = "/dev/tty%d";
+ char name[64];
+ int size, flags;
+
+ size = snprintf(name, sizeof(name), tty, vtno);
+ if (size >= sizeof(name))
+ return -1;
+
+ flags = (vtno) ? O_RDWR | O_NDELAY : O_WRONLY;
+
+ return open(name, flags);
+}
+
+static int tty_switch_vt(int fd, int vtno)
+{
+ int ret;
+
+ ret = ioctl(fd, VT_ACTIVATE, vtno);
+ if (ret >= 0)
+ ret = ioctl(fd, VT_WAITACTIVE, vtno);
+
+ return ret;
+}
+
+
+static int tty_init_vt(void)
+{
+ struct vt_stat vts;
+ int fd, vtno;
+
+ /* get the next available tty number */
+ fd = tty_open_vt(0);
+ if (fd < 0)
+ return -1;
+ if (ioctl(fd, VT_OPENQRY, &vtno) < 0)
+ goto fail;
+ close(fd);
+
+ fd = tty_open_vt(vtno);
+ if (fd < 0)
+ return -1;
+
+ /* save the current VT */
+ if (ioctl(fd, VT_GETSTATE, &vts) < 0)
+ goto fail;
+ tty_saved_vtno = vts.v_active;
+
+ if (tty_switch_vt(fd, vtno))
+ goto fail;
+
+ return fd;
+
+fail:
+ close(fd);
+ return -1;
+}
+
+static void
+tty_close(void)
+{
+ /* restore */
+ ioctl(tty_fd, KDSETMODE, KD_TEXT);
+ tty_switch_vt(tty_fd, tty_saved_vtno);
+
+ close(tty_fd);
+}
+
+static void
+signal_handler(int sig)
+{
+ if (tty_fd >= 0)
+ tty_close();
+}
+
+static int tty_open(void)
+{
+ struct sigaction sa;
+
+ tty_fd = tty_init_vt();
+ if (tty_fd < 0)
+ return -1;
+
+ /* install the signal handler */
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = signal_handler;
+ if (sigaction(SIGINT, &sa, NULL))
+ goto fail;
+ if (sigaction(SIGTERM, &sa, NULL))
+ goto fail;
+ if (sigaction(SIGABRT, &sa, NULL))
+ goto fail;
+
+ if (ioctl(tty_fd, KDSETMODE, KD_GRAPHICS) < 0)
+ goto fail;
+
+ tcflush(tty_fd, TCIOFLUSH);
+
+ return 0;
+
+fail:
+ tty_close();
+ tty_fd = -1;
+ return -1;
+}
+
+static EGLDisplay egl_dpy;
+static EGLContext egl_ctx;
+static EGLSurface egl_surf;
+static EGLBoolean egl_verbose;
+
+static void
+egl_fatal(char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ putc('\n', stderr);
+
+ abort();
+}
+
+static void
+egl_init_for_fbdev(int fd, EGLBoolean verbose)
+{
+ const EGLNativeWindowType native_win = (EGLNativeWindowType) NULL;
+ EGLint major, minor, num_configs;
+ EGLConfig conf;
+
+ egl_verbose = verbose;
+
+ /* make Mesa/EGL happy */
+ setenv("EGL_PLATFORM", "fbdev", 0);
+
+ egl_dpy = eglGetDisplay((EGLNativeDisplayType) fd);
+ if (egl_dpy == EGL_NO_DISPLAY)
+ egl_fatal("failed to get a display");
+ if (!eglInitialize(egl_dpy, &major, &minor))
+ egl_fatal("failed to initialize EGL");
+
+ if (egl_verbose) {
+ printf("EGL %d.%d\n", major, minor);
+ printf("EGL_VENDOR: %s\n", eglQueryString(egl_dpy, EGL_VENDOR));
+ printf("EGL_VERSION: %s\n", eglQueryString(egl_dpy, EGL_VERSION));
+ printf("EGL_EXTENSIONS: %s\n", eglQueryString(egl_dpy, EGL_EXTENSIONS));
+ printf("EGL_CLIENT_APIS: %s\n",
+ eglQueryString(egl_dpy, EGL_CLIENT_APIS));
+ }
+
+ if (!eglChooseConfig(egl_dpy, NULL, &conf, 1, &num_configs) ||
+ !num_configs)
+ egl_fatal("failed to choose a config");
+
+ egl_ctx = eglCreateContext(egl_dpy, conf, EGL_NO_CONTEXT, NULL);
+ if (egl_ctx == EGL_NO_CONTEXT)
+ egl_fatal("failed to create a context");
+
+ egl_surf = eglCreateWindowSurface(egl_dpy, conf, native_win, NULL);
+ if (egl_surf == EGL_NO_SURFACE)
+ egl_fatal("failed to create a surface");
+
+ if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
+ egl_fatal("failed to make context/surface current");
+}
+
+static void
+egl_present(void)
+{
+ if (!eglSwapBuffers(egl_dpy, egl_surf))
+ egl_fatal("failed to swap buffers");
+}
+
+static void
+egl_destroy(void)
+{
+ eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(egl_dpy, egl_surf);
+ eglDestroyContext(egl_dpy, egl_ctx);
+ eglTerminate(egl_dpy);
+
+ egl_surf = EGL_NO_SURFACE;
+ egl_ctx = EGL_NO_CONTEXT;
+ egl_dpy = EGL_NO_DISPLAY;
+}
+
+/* stolen from tri.c */
+static void
+draw(int frame)
+{
+ static const GLfloat verts[3][2] = {
+ { -1, -1 },
+ { 1, -1 },
+ { 0, 1 }
+ };
+ static const GLfloat colors[3][4] = {
+ { 1, 0, 0, 1 },
+ { 0, 1, 0, 1 },
+ { 0, 0, 1, 1 }
+ };
+ GLfloat view_rotz = (GLfloat) frame;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(view_rotz, 0, 0, 1);
+
+ glVertexPointer(2, GL_FLOAT, 0, verts);
+ glColorPointer(4, GL_FLOAT, 0, colors);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ /* draw triangle */
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glPopMatrix();
+}
+
+static void
+init(int width, int height)
+{
+ GLfloat ar = (GLfloat) width / height;
+
+ glViewport(0, 0, width, height);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -10.0);
+}
+
+int
+main(int argc, char **argv)
+{
+ const char fbdev[] = "/dev/fb0";
+ struct fb_var_screeninfo vinfo;
+ int fd, tty_err, frame;
+
+ fd = open(fbdev, O_RDWR);
+ if (fd < 0)
+ egl_fatal("failed to open %s", fbdev);
+
+ memset(&vinfo, 0, sizeof(vinfo));
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo))
+ egl_fatal("failed to get fb info");
+
+ /* initialize EGL */
+ egl_init_for_fbdev(fd, EGL_TRUE);
+
+ /* try to open a new tty */
+ tty_err = tty_open();
+
+ init(vinfo.xres, vinfo.yres);
+ for (frame = 0; frame <= 180; frame++) {
+ draw(frame);
+ egl_present();
+ }
+
+ if (!tty_err)
+ tty_close();
+
+ egl_destroy();
+ close(fd);
+
+ return 0;
+}