/* * 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 */ /* * 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 #include #include #include /* for tty */ #include #include #include #include #include #include /* for fbdev */ #include #include #include #include /* for EGL */ #include #include 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; }