progs/egl: Add eglut.

eglut is a simple library with GLUT-like API.  It is intended to be used
by simple EGL demos.
This commit is contained in:
Chia-I Wu
2010-04-01 12:19:47 +08:00
parent fc3ddd4b56
commit 57cc1db87b
6 changed files with 880 additions and 0 deletions

35
progs/egl/eglut/Makefile Normal file
View File

@@ -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

326
progs/egl/eglut/eglut.c Normal file
View File

@@ -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;
}

67
progs/egl/eglut/eglut.h Normal file
View File

@@ -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 */

View File

@@ -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++;
}
}
}

220
progs/egl/eglut/eglut_x11.c Normal file
View File

@@ -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);
}
}
}

View File

@@ -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_ */