diff options
-rw-r--r-- | progs/egl/eglut/Makefile | 35 | ||||
-rw-r--r-- | progs/egl/eglut/eglut.c | 326 | ||||
-rw-r--r-- | progs/egl/eglut/eglut.h | 67 | ||||
-rw-r--r-- | progs/egl/eglut/eglut_screen.c | 154 | ||||
-rw-r--r-- | progs/egl/eglut/eglut_x11.c | 220 | ||||
-rw-r--r-- | progs/egl/eglut/eglutint.h | 78 |
6 files changed, 880 insertions, 0 deletions
diff --git a/progs/egl/eglut/Makefile b/progs/egl/eglut/Makefile new file mode 100644 index 0000000000..f5cafa7010 --- /dev/null +++ b/progs/egl/eglut/Makefile @@ -0,0 +1,35 @@ +# progs/egl/eglut + +TOP = ../../.. +include $(TOP)/configs/current + +INCLUDES = \ + -I$(TOP)/include + +SOURCES = $(wildcard *.c) + +EGLUT_X11_OBJECTS = eglut.o eglut_x11.o +EGLUT_SCREEN_OBJECTS = eglut.o eglut_screen.o + +default: depend libeglut-x11.a libeglut-screen.a + +libeglut-x11.a: $(EGLUT_X11_OBJECTS) + $(MKLIB) -o eglut-x11 -static $(EGLUT_X11_OBJECTS) + +libeglut-screen.a: $(EGLUT_SCREEN_OBJECTS) + $(MKLIB) -o eglut-screen -static $(EGLUT_SCREEN_OBJECTS) + +.c.o: + $(CC) -c -o $@ $< $(INCLUDES) $(DEFINES) $(CFLAGS) + +depend: $(SOURCES) + @rm -f depend + @touch depend + @$(MKDEP) $(MKDEP_OPTIONS) $(INCLUDES) $(SOURCES) \ + > /dev/null 2>/dev/null + +clean: + rm -f *.o *.a + rm -f depend depend.bak + +sinclude depend diff --git a/progs/egl/eglut/eglut.c b/progs/egl/eglut/eglut.c new file mode 100644 index 0000000000..0bfd5d5b06 --- /dev/null +++ b/progs/egl/eglut/eglut.c @@ -0,0 +1,326 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <sys/time.h> + +#include "EGL/egl.h" +#include "EGL/eglext.h" + +#include "eglutint.h" + +static struct eglut_state _eglut_state = { + .api_mask = EGLUT_OPENGL_ES1_BIT, + .window_width = 300, + .window_height = 300, + .verbose = 0, + .num_windows = 0, +}; + +struct eglut_state *_eglut = &_eglut_state; + +void +_eglutFatal(char *format, ...) +{ + va_list args; + + va_start(args, format); + + fprintf(stderr, "EGLUT: "); + vfprintf(stderr, format, args); + va_end(args); + putc('\n', stderr); + + exit(1); +} + +/* return current time (in milliseconds) */ +int +_eglutNow(void) +{ + struct timeval tv; +#ifdef __VMS + (void) gettimeofday(&tv, NULL ); +#else + struct timezone tz; + (void) gettimeofday(&tv, &tz); +#endif + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static void +_eglutDestroyWindow(struct eglut_window *win) +{ + if (_eglut->surface_type != EGL_PBUFFER_BIT && + _eglut->surface_type != EGL_SCREEN_BIT_MESA) + eglDestroySurface(_eglut->dpy, win->surface); + + _eglutNativeFiniWindow(win); + + eglDestroyContext(_eglut->dpy, win->context); +} + +static EGLConfig +_eglutChooseConfig(void) +{ + EGLConfig config; + EGLint config_attribs[32]; + EGLint renderable_type, num_configs, i; + + i = 0; + config_attribs[i++] = EGL_RED_SIZE; + config_attribs[i++] = 1; + config_attribs[i++] = EGL_GREEN_SIZE; + config_attribs[i++] = 1; + config_attribs[i++] = EGL_BLUE_SIZE; + config_attribs[i++] = 1; + config_attribs[i++] = EGL_DEPTH_SIZE; + config_attribs[i++] = 1; + + config_attribs[i++] = EGL_SURFACE_TYPE; + config_attribs[i++] = _eglut->surface_type; + + config_attribs[i++] = EGL_RENDERABLE_TYPE; + renderable_type = 0x0; + if (_eglut->api_mask & EGLUT_OPENGL_BIT) + renderable_type |= EGL_OPENGL_BIT; + if (_eglut->api_mask & (EGLUT_OPENGL_ES1_BIT | EGLUT_OPENGL_ES2_BIT)) + renderable_type |= EGL_OPENGL_ES_BIT; + if (_eglut->api_mask & EGLUT_OPENVG_BIT) + renderable_type |= EGL_OPENVG_BIT; + config_attribs[i++] = renderable_type; + + config_attribs[i] = EGL_NONE; + + if (!eglChooseConfig(_eglut->dpy, + config_attribs, &config, 1, &num_configs) || !num_configs) + _eglutFatal("failed to choose a config"); + + return config; +} + +static struct eglut_window * +_eglutCreateWindow(const char *title, int x, int y, int w, int h) +{ + struct eglut_window *win; + EGLint context_attribs[4]; + EGLint api, i; + + win = calloc(1, sizeof(*win)); + if (!win) + _eglutFatal("failed to allocate window"); + + win->config = _eglutChooseConfig(); + + i = 0; + context_attribs[i] = EGL_NONE; + + /* multiple APIs? */ + + api = EGL_OPENGL_ES_API; + if (_eglut->api_mask & EGLUT_OPENGL_BIT) { + api = EGL_OPENGL_API; + } + else if (_eglut->api_mask & EGLUT_OPENVG_BIT) { + api = EGL_OPENVG_API; + } + else if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT) { + context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION; + context_attribs[i++] = 2; + } + + context_attribs[i] = EGL_NONE; + + eglBindAPI(api); + win->context = eglCreateContext(_eglut->dpy, + win->config, EGL_NO_CONTEXT, context_attribs); + if (!win->context) + _eglutFatal("failed to create context"); + + _eglutNativeInitWindow(win, title, x, y, w, h); + switch (_eglut->surface_type) { + case EGL_WINDOW_BIT: + win->surface = eglCreateWindowSurface(_eglut->dpy, + win->config, win->native.u.window, NULL); + break; + case EGL_PIXMAP_BIT: + win->surface = eglCreatePixmapSurface(_eglut->dpy, + win->config, win->native.u.pixmap, NULL); + break; + case EGL_PBUFFER_BIT: + case EGL_SCREEN_BIT_MESA: + win->surface = win->native.u.surface; + break; + default: + break; + } + if (win->surface == EGL_NO_SURFACE) + _eglutFatal("failed to create surface"); + + return win; +} + +void +eglutInitAPIMask(int mask) +{ + _eglut->api_mask = mask; +} + +void +eglutInitWindowSize(int width, int height) +{ + _eglut->window_width = width; + _eglut->window_height = height; +} + +void +eglutInit(int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-display") == 0) + _eglut->display_name = argv[++i]; + else if (strcmp(argv[i], "-info") == 0) { + _eglut->verbose = 1; + } + } + + _eglutNativeInitDisplay(); + _eglut->dpy = eglGetDisplay(_eglut->native_dpy); + + if (!eglInitialize(_eglut->dpy, &_eglut->major, &_eglut->minor)) + _eglutFatal("failed to initialize EGL display"); + + _eglut->init_time = _eglutNow(); + + printf("EGL_VERSION = %s\n", eglQueryString(_eglut->dpy, EGL_VERSION)); +} + +int +eglutGet(int state) +{ + int val; + + switch (state) { + case EGLUT_ELAPSED_TIME: + val = _eglutNow() - _eglut->init_time; + break; + default: + val = -1; + break; + } + + return val; +} + +void +eglutIdleFunc(EGLUTidleCB func) +{ + _eglut->idle_cb = func; +} + +void +eglutPostRedisplay(void) +{ + _eglut->redisplay = 1; +} + +void +eglutMainLoop(void) +{ + struct eglut_window *win = _eglut->current; + + if (!win) + _eglutFatal("no window is created\n"); + + if (win->reshape_cb) + win->reshape_cb(win->native.width, win->native.height); + + _eglutNativeEventLoop(); +} + +static void +_eglutFini(void) +{ + eglTerminate(_eglut->dpy); + _eglutNativeFiniDisplay(); +} + +static void +_eglutDefaultKeyboard(unsigned char key) +{ + if (key == 27) { + /* XXX it causes some bug in st/egl KMS backend */ + if ( _eglut->surface_type != EGL_SCREEN_BIT_MESA) + eglMakeCurrent(_eglut->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + _eglutDestroyWindow(_eglut->current); + _eglutFini(); + + exit(0); + } +} + +int +eglutCreateWindow(const char *title) +{ + struct eglut_window *win; + + win = _eglutCreateWindow(title, 0, 0, + _eglut->window_width, _eglut->window_height); + + win->index = _eglut->num_windows++; + win->reshape_cb = NULL; + win->display_cb = NULL; + win->keyboard_cb = _eglutDefaultKeyboard; + win->special_cb = NULL; + + if (!eglMakeCurrent(_eglut->dpy, win->surface, win->surface, win->context)) + _eglutFatal("failed to make window current"); + _eglut->current = win; + + return win->index; +} + +int +eglutGetWindowWidth(void) +{ + struct eglut_window *win = _eglut->current; + return win->native.width; +} + +int +eglutGetWindowHeight(void) +{ + struct eglut_window *win = _eglut->current; + return win->native.height; +} + +void +eglutDisplayFunc(EGLUTdisplayCB func) +{ + struct eglut_window *win = _eglut->current; + win->display_cb = func; + +} + +void +eglutReshapeFunc(EGLUTreshapeCB func) +{ + struct eglut_window *win = _eglut->current; + win->reshape_cb = func; +} + +void +eglutKeyboardFunc(EGLUTkeyboardCB func) +{ + struct eglut_window *win = _eglut->current; + win->keyboard_cb = func; +} + +void +eglutSpecialFunc(EGLUTspecialCB func) +{ + struct eglut_window *win = _eglut->current; + win->special_cb = func; +} diff --git a/progs/egl/eglut/eglut.h b/progs/egl/eglut/eglut.h new file mode 100644 index 0000000000..521cc12eab --- /dev/null +++ b/progs/egl/eglut/eglut.h @@ -0,0 +1,67 @@ +#ifndef EGLUT_H +#define EGLUT_H + +/* used by eglutInitAPIMask */ +enum { + EGLUT_OPENGL_BIT = 0x1, + EGLUT_OPENGL_ES1_BIT = 0x2, + EGLUT_OPENGL_ES2_BIT = 0x4, + EGLUT_OPENVG_BIT = 0x8 +}; + +/* used by EGLUTspecialCB */ +enum { + /* function keys */ + EGLUT_KEY_F1, + EGLUT_KEY_F2, + EGLUT_KEY_F3, + EGLUT_KEY_F4, + EGLUT_KEY_F5, + EGLUT_KEY_F6, + EGLUT_KEY_F7, + EGLUT_KEY_F8, + EGLUT_KEY_F9, + EGLUT_KEY_F10, + EGLUT_KEY_F11, + EGLUT_KEY_F12, + + /* directional keys */ + EGLUT_KEY_LEFT, + EGLUT_KEY_UP, + EGLUT_KEY_RIGHT, + EGLUT_KEY_DOWN, +}; + +/* used by eglutGet */ +enum { + EGLUT_ELAPSED_TIME +}; + +typedef void (*EGLUTidleCB)(void); +typedef void (*EGLUTreshapeCB)(int, int); +typedef void (*EGLUTdisplayCB)(void); +typedef void (*EGLUTkeyboardCB)(unsigned char); +typedef void (*EGLUTspecialCB)(int); + +void eglutInitAPIMask(int mask); +void eglutInitWindowSize(int width, int height); +void eglutInit(int argc, char **argv); + +int eglutGet(int state); + +void eglutIdleFunc(EGLUTidleCB func); +void eglutPostRedisplay(void); + +void eglutMainLoop(void); + +int eglutCreateWindow(const char *title); + +int eglutGetWindowWidth(void); +int eglutGetWindowHeight(void); + +void eglutDisplayFunc(EGLUTdisplayCB func); +void eglutReshapeFunc(EGLUTreshapeCB func); +void eglutKeyboardFunc(EGLUTkeyboardCB func); +void eglutSpecialFunc(EGLUTspecialCB func); + +#endif /* EGLUT_H */ diff --git a/progs/egl/eglut/eglut_screen.c b/progs/egl/eglut/eglut_screen.c new file mode 100644 index 0000000000..50549e4bcf --- /dev/null +++ b/progs/egl/eglut/eglut_screen.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <string.h> +#include <sys/time.h> + +#define EGL_EGLEXT_PROTOTYPES +#include "EGL/egl.h" +#include "EGL/eglext.h" + +#include "eglutint.h" + +#define MAX_MODES 100 + +static EGLScreenMESA kms_screen; +static EGLModeMESA kms_mode; +static EGLint kms_width, kms_height; + +void +_eglutNativeInitDisplay(void) +{ + _eglut->native_dpy = EGL_DEFAULT_DISPLAY; + _eglut->surface_type = EGL_SCREEN_BIT_MESA; +} + +void +_eglutNativeFiniDisplay(void) +{ + kms_screen = 0; + kms_mode = 0; + kms_width = 0; + kms_height = 0; +} + +static void +init_kms(void) +{ + EGLModeMESA modes[MAX_MODES]; + EGLint num_screens, num_modes; + EGLint width, height, best_mode; + EGLint i; + + if (!eglGetScreensMESA(_eglut->dpy, &kms_screen, 1, &num_screens) || + !num_screens) + _eglutFatal("eglGetScreensMESA failed\n"); + + if (!eglGetModesMESA(_eglut->dpy, kms_screen, + modes, MAX_MODES, &num_modes) || !num_modes) + _eglutFatal("eglGetModesMESA failed!\n"); + + printf("Found %d modes:\n", num_modes); + + best_mode = 0; + width = 0; + height = 0; + for (i = 0; i < num_modes; i++) { + EGLint w, h; + eglGetModeAttribMESA(_eglut->dpy, modes[i], EGL_WIDTH, &w); + eglGetModeAttribMESA(_eglut->dpy, modes[i], EGL_HEIGHT, &h); + printf("%3d: %d x %d\n", i, w, h); + if (w > width && h > height) { + width = w; + height = h; + best_mode = i; + } + } + + printf("Will use screen size: %d x %d\n", width, height); + + kms_mode = modes[best_mode]; + kms_width = width; + kms_height = height; +} + +void +_eglutNativeInitWindow(struct eglut_window *win, const char *title, + int x, int y, int w, int h) +{ + EGLint surf_attribs[16]; + EGLint i; + const char *exts; + + exts = eglQueryString(_eglut->dpy, EGL_EXTENSIONS); + if (!exts || !strstr(exts, "EGL_MESA_screen_surface")) + _eglutFatal("EGL_MESA_screen_surface is not supported\n"); + + init_kms(); + + i = 0; + surf_attribs[i++] = EGL_WIDTH; + surf_attribs[i++] = kms_width; + surf_attribs[i++] = EGL_HEIGHT; + surf_attribs[i++] = kms_height; + surf_attribs[i++] = EGL_NONE; + + /* create surface */ + win->native.u.surface = eglCreateScreenSurfaceMESA(_eglut->dpy, + win->config, surf_attribs); + if (win->native.u.surface == EGL_NO_SURFACE) + _eglutFatal("eglCreateScreenSurfaceMESA failed\n"); + + if (!eglShowScreenSurfaceMESA(_eglut->dpy, kms_screen, + win->native.u.surface, kms_mode)) + _eglutFatal("eglShowScreenSurfaceMESA failed\n"); + + win->native.width = kms_width; + win->native.height = kms_height; +} + +void +_eglutNativeFiniWindow(struct eglut_window *win) +{ + eglShowScreenSurfaceMESA(_eglut->dpy, + kms_screen, EGL_NO_SURFACE, 0); + eglDestroySurface(_eglut->dpy, win->native.u.surface); +} + +void +_eglutNativeEventLoop(void) +{ + int start = _eglutNow(); + int frames = 0; + + _eglut->redisplay = 1; + + while (1) { + struct eglut_window *win = _eglut->current; + int now = _eglutNow(); + + if (now - start > 5000) { + double elapsed = (double) (now - start) / 1000.0; + + printf("%d frames in %3.1f seconds = %6.3f FPS\n", + frames, elapsed, frames / elapsed); + + start = now; + frames = 0; + + /* send escape */ + if (win->keyboard_cb) + win->keyboard_cb(27); + } + + if (_eglut->idle_cb) + _eglut->idle_cb(); + + if (_eglut->redisplay) { + _eglut->redisplay = 0; + + if (win->display_cb) + win->display_cb(); + eglSwapBuffers(_eglut->dpy, win->surface); + frames++; + } + } +} diff --git a/progs/egl/eglut/eglut_x11.c b/progs/egl/eglut/eglut_x11.c new file mode 100644 index 0000000000..f3b2280374 --- /dev/null +++ b/progs/egl/eglut/eglut_x11.c @@ -0,0 +1,220 @@ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> + +#include "eglutint.h" + +void +_eglutNativeInitDisplay(void) +{ + _eglut->native_dpy = XOpenDisplay(_eglut->display_name); + if (!_eglut->native_dpy) + _eglutFatal("failed to initialize native display"); + + _eglut->surface_type = EGL_WINDOW_BIT; +} + +void +_eglutNativeFiniDisplay(void) +{ + XCloseDisplay(_eglut->native_dpy); +} + +void +_eglutNativeInitWindow(struct eglut_window *win, const char *title, + int x, int y, int w, int h) +{ + XVisualInfo *visInfo, visTemplate; + int num_visuals; + Window root, xwin; + XSetWindowAttributes attr; + unsigned long mask; + EGLint vid; + + if (!eglGetConfigAttrib(_eglut->dpy, + win->config, EGL_NATIVE_VISUAL_ID, &vid)) + _eglutFatal("failed to get visual id"); + + /* The X window visual must match the EGL config */ + visTemplate.visualid = vid; + visInfo = XGetVisualInfo(_eglut->native_dpy, + VisualIDMask, &visTemplate, &num_visuals); + if (!visInfo) + _eglutFatal("failed to get an visual of id 0x%x", vid); + + root = RootWindow(_eglut->native_dpy, DefaultScreen(_eglut->native_dpy)); + + /* window attributes */ + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(_eglut->native_dpy, + root, visInfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + xwin = XCreateWindow(_eglut->native_dpy, root, x, y, w, h, + 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); + if (!xwin) + _eglutFatal("failed to create a window"); + + XFree(visInfo); + + /* set hints and properties */ + { + XSizeHints sizehints; + sizehints.x = x; + sizehints.y = y; + sizehints.width = w; + sizehints.height = h; + sizehints.flags = USSize | USPosition; + XSetNormalHints(_eglut->native_dpy, xwin, &sizehints); + XSetStandardProperties(_eglut->native_dpy, xwin, + title, title, None, (char **) NULL, 0, &sizehints); + } + + XMapWindow(_eglut->native_dpy, xwin); + + win->native.u.window = xwin; + win->native.width = w; + win->native.height = h; +} + +void +_eglutNativeFiniWindow(struct eglut_window *win) +{ + XDestroyWindow(_eglut->native_dpy, win->native.u.window); +} + +static int +lookup_keysym(KeySym sym) +{ + int special; + + switch (sym) { + case XK_F1: + special = EGLUT_KEY_F1; + break; + case XK_F2: + special = EGLUT_KEY_F2; + break; + case XK_F3: + special = EGLUT_KEY_F3; + break; + case XK_F4: + special = EGLUT_KEY_F4; + break; + case XK_F5: + special = EGLUT_KEY_F5; + break; + case XK_F6: + special = EGLUT_KEY_F6; + break; + case XK_F7: + special = EGLUT_KEY_F7; + break; + case XK_F8: + special = EGLUT_KEY_F8; + break; + case XK_F9: + special = EGLUT_KEY_F9; + break; + case XK_F10: + special = EGLUT_KEY_F10; + break; + case XK_F11: + special = EGLUT_KEY_F11; + break; + case XK_F12: + special = EGLUT_KEY_F12; + break; + case XK_KP_Left: + case XK_Left: + special = EGLUT_KEY_LEFT; + break; + case XK_KP_Up: + case XK_Up: + special = EGLUT_KEY_UP; + break; + case XK_KP_Right: + case XK_Right: + special = EGLUT_KEY_RIGHT; + break; + case XK_KP_Down: + case XK_Down: + special = EGLUT_KEY_DOWN; + break; + default: + special = -1; + break; + } + + return special; +} + +static void +next_event(struct eglut_window *win) +{ + int redraw = 0; + XEvent event; + + if (!XPending(_eglut->native_dpy)) { + if (_eglut->idle_cb) + _eglut->idle_cb(); + return; + } + + XNextEvent(_eglut->native_dpy, &event); + + switch (event.type) { + case Expose: + redraw = 1; + break; + case ConfigureNotify: + win->native.width = event.xconfigure.width; + win->native.height = event.xconfigure.height; + if (win->reshape_cb) + win->reshape_cb(win->native.width, win->native.height); + break; + case KeyPress: + { + char buffer[1]; + KeySym sym; + int r; + + r = XLookupString(&event.xkey, + buffer, sizeof(buffer), &sym, NULL); + if (r && win->keyboard_cb) { + win->keyboard_cb(buffer[0]); + } + else if (!r && win->special_cb) { + r = lookup_keysym(sym); + if (r >= 0) + win->special_cb(r); + } + } + redraw = 1; + break; + default: + ; /*no-op*/ + } + + _eglut->redisplay = redraw; +} + +void +_eglutNativeEventLoop(void) +{ + while (1) { + struct eglut_window *win = _eglut->current; + + next_event(win); + + if (_eglut->redisplay) { + _eglut->redisplay = 0; + + if (win->display_cb) + win->display_cb(); + eglSwapBuffers(_eglut->dpy, win->surface); + } + } +} diff --git a/progs/egl/eglut/eglutint.h b/progs/egl/eglut/eglutint.h new file mode 100644 index 0000000000..54d329f328 --- /dev/null +++ b/progs/egl/eglut/eglutint.h @@ -0,0 +1,78 @@ +#ifndef _EGLUTINT_H_ +#define _EGLUTINT_H_ + +#include "EGL/egl.h" +#include "eglut.h" + +struct eglut_window { + EGLConfig config; + EGLContext context; + + /* initialized by native display */ + struct { + union { + EGLNativeWindowType window; + EGLNativePixmapType pixmap; + EGLSurface surface; /* pbuffer or screen surface */ + } u; + int width, height; + } native; + + EGLSurface surface; + + int index; + + EGLUTreshapeCB reshape_cb; + EGLUTdisplayCB display_cb; + EGLUTkeyboardCB keyboard_cb; + EGLUTspecialCB special_cb; +}; + +struct eglut_state { + int api_mask; + int window_width, window_height; + const char *display_name; + int verbose; + int init_time; + + EGLUTidleCB idle_cb; + + int num_windows; + + /* initialized by native display */ + EGLNativeDisplayType native_dpy; + EGLint surface_type; + + EGLDisplay dpy; + EGLint major, minor; + + struct eglut_window *current; + + int redisplay; +}; + +extern struct eglut_state *_eglut; + +void +_eglutFatal(char *format, ...); + +int +_eglutNow(void); + +void +_eglutNativeInitDisplay(void); + +void +_eglutNativeFiniDisplay(void); + +void +_eglutNativeInitWindow(struct eglut_window *win, const char *title, + int x, int y, int w, int h); + +void +_eglutNativeFiniWindow(struct eglut_window *win); + +void +_eglutNativeEventLoop(void); + +#endif /* _EGLUTINT_H_ */ |