Files
commandergenius/project/jni/glshim/src/glx/glx.c
2016-10-22 21:12:58 +03:00

1619 lines
52 KiB
C
Executable File

#ifndef ANDROID
#include <execinfo.h>
#endif
#include <fcntl.h>
#if defined(PANDORA) || defined(ODROID)
#define USE_FBIO 1
#endif
#ifdef USE_FBIO
#include <linux/fb.h>
#endif
#ifdef PANDORA
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
#include "glx.h"
#include "utils.h"
//#include <GLES/gl.h>
#include "../gl/gl.h"
#include "../glx/streaming.h"
#include "khash.h"
#define EXPORT __attribute__((visibility("default")))
#ifndef EGL_GL_COLORSPACE_KHR
#define EGL_GL_COLORSPACE_KHR 0x309D
#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
#endif
static bool eglInitialized = false;
static EGLDisplay eglDisplay;
static EGLSurface eglSurface;
static EGLConfig eglConfigs[1];
static int glx_default_depth=0;
static int glx_surface_srgb=0; // default to not try to create an sRGB surface
#ifdef PANDORA
static struct sockaddr_un sun;
static int sock = -2;
#endif
typedef struct {int Width; int Height; EGLContext Context;} glx_buffSize;
#ifndef ANDROID
//PBuffer should work under ANDROID
static GLXPbuffer *pbufferlist = NULL;
static glx_buffSize *pbuffersize = NULL;
static int pbufferlist_cap = 0;
static int pbufferlist_size = 0;
static int isPBuffer(GLXDrawable drawable) {
for (int i=0; i<pbufferlist_size; i++)
if(pbufferlist[i]==(GLXPbuffer)drawable)
return i+1;
return 0;
}
#endif
static EGLint egl_context_attrib[] = {
#ifdef USE_ES2
EGL_CONTEXT_CLIENT_VERSION, 2,
#endif
EGL_NONE
};
extern void* egl;
// GLState management
void* NewGLState(void* shared_glstate);
void DeleteGLState(void* oldstate);
void ActivateGLState(void* new_glstate);
typedef struct {
int drawable;
EGLSurface surface;
int PBuffer;
} map_drawable_t;
KHASH_MAP_INIT_INT(mapdrawable, map_drawable_t*)
khash_t(mapdrawable) *MapDrawable = NULL;
int8_t CheckEGLErrors() {
EGLenum error;
char *errortext;
LOAD_EGL(eglGetError);
error = egl_eglGetError();
if (error != EGL_SUCCESS && error != 0) {
switch (error) {
case EGL_NOT_INITIALIZED: errortext = "EGL_NOT_INITIALIZED"; break;
case EGL_BAD_ACCESS: errortext = "EGL_BAD_ACCESS"; break;
case EGL_BAD_ALLOC: errortext = "EGL_BAD_ALLOC"; break;
case EGL_BAD_ATTRIBUTE: errortext = "EGL_BAD_ATTRIBUTE"; break;
case EGL_BAD_CONTEXT: errortext = "EGL_BAD_CONTEXT"; break;
case EGL_BAD_CONFIG: errortext = "EGL_BAD_CONFIG"; break;
case EGL_BAD_CURRENT_SURFACE: errortext = "EGL_BAD_CURRENT_SURFACE"; break;
case EGL_BAD_DISPLAY: errortext = "EGL_BAD_DISPLAY"; break;
case EGL_BAD_SURFACE: errortext = "EGL_BAD_SURFACE"; break;
case EGL_BAD_MATCH: errortext = "EGL_BAD_MATCH"; break;
case EGL_BAD_PARAMETER: errortext = "EGL_BAD_PARAMETER"; break;
case EGL_BAD_NATIVE_PIXMAP: errortext = "EGL_BAD_NATIVE_PIXMAP"; break;
case EGL_BAD_NATIVE_WINDOW: errortext = "EGL_BAD_NATIVE_WINDOW"; break;
default: errortext = "unknown"; break;
}
printf("LIBGL: ERROR: EGL Error detected: %s (0x%X)\n", errortext, error);
return 1;
}
return 0;
}
#ifndef ANDROID
static int get_config_default(Display *display, int attribute, int *value) {
switch (attribute) {
case GLX_USE_GL:
case GLX_RGBA:
case GLX_DOUBLEBUFFER:
*value = 1;
break;
case GLX_LEVEL:
case GLX_STEREO:
*value = 0;
break;
case GLX_AUX_BUFFERS:
*value = 0;
break;
case GLX_RED_SIZE:
*value = 5;
break;
case GLX_GREEN_SIZE:
*value = 6;
break;
case GLX_BLUE_SIZE:
*value = 5;
break;
case GLX_ALPHA_SIZE:
*value = 8;
break;
case GLX_DEPTH_SIZE:
*value = 16;
break;
case GLX_STENCIL_SIZE:
case GLX_ACCUM_RED_SIZE:
case GLX_ACCUM_GREEN_SIZE:
case GLX_ACCUM_BLUE_SIZE:
case GLX_ACCUM_ALPHA_SIZE:
*value = 0;
break;
case GLX_TRANSPARENT_TYPE:
*value = GLX_NONE;
break;
case GLX_RENDER_TYPE:
*value = GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT;
break;
case GLX_VISUAL_ID:
*value = glXChooseVisual(display, 0, NULL)->visualid;
//*value = 1;
break;
case GLX_FBCONFIG_ID:
*value = 1;
break;
case GLX_DRAWABLE_TYPE:
*value = GLX_WINDOW_BIT;
break;
case GLX_BUFFER_SIZE:
*value = 16;
break;
case GLX_X_VISUAL_TYPE:
case GLX_CONFIG_CAVEAT:
case GLX_SAMPLE_BUFFERS:
case GLX_SAMPLES:
*value = 0;
break;
case GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB:
*value = 0;
break;
default:
printf("LIBGL: unknown attrib %i\n", attribute);
*value = 0;
return 1;
}
return 0;
}
static Display *g_display = NULL;
static GLXContext glxContext = NULL;
static GLXContext fbContext = NULL;
#endif //ANDROID
// hmm...
static EGLContext eglContext;
static int fbcontext_count = 0;
#ifdef USE_FBIO
#ifndef FBIO_WAITFORVSYNC
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
#endif
#ifdef PANDORA
static float pandora_gamma = 0.0f;
#endif
static int fbdev = -1;
static bool g_vsync = false;
#endif
static bool g_showfps = false;
static bool g_usefb = false;
static bool g_usefbo = false;
static bool g_xrefresh = false;
static bool g_stacktrace = false;
extern int automipmap;
extern int texcopydata;
extern int tested_env;
extern int texshrink;
extern int texdump;
extern int alphahack;
extern int texstream;
extern int copytex;
extern int nolumalpha;
extern int blendhack;
extern int export_blendcolor;
extern int glshim_noerror;
extern char glshim_version[50];
extern int glshim_nobanner;
extern int glshim_npot;
int export_silentstub = 0;
int glshim_queries = 0;
bool g_recyclefbo = false;
static int g_width=0, g_height=0;
// RPI stuffs
static bool g_bcmhost = false;
static bool g_bcm_active = false;
void (*bcm_host_init)();
void (*bcm_host_deinit)();
#define SHUT(a) if(!glshim_nobanner) a
static int swap_interval = 1;
#ifndef ANDROID
static void init_display(Display *display) {
LOAD_EGL(eglGetDisplay);
if (! g_display) {
g_display = display;//XOpenDisplay(NULL);
}
if (g_usefb) {
eglDisplay = egl_eglGetDisplay(EGL_DEFAULT_DISPLAY);
} else {
eglDisplay = egl_eglGetDisplay(display);
}
}
#endif //ANDROID
static void init_vsync() {
#ifdef USE_FBIO
fbdev = open("/dev/fb0", O_RDONLY);
if (fbdev < 0) {
fprintf(stderr, "LIBGL: Could not open /dev/fb0 for vsync.\n");
}
#endif
}
static void xrefresh() {
int dummy = system("xrefresh");
}
#ifdef PANDORA
static void pandora_reset_gamma() {
if(pandora_gamma>0.0f)
system("sudo /usr/pandora/scripts/op_gamma.sh 0");
}
static void pandora_set_gamma() {
if(pandora_gamma>0.0f) {
char buf[50];
sprintf(buf, "sudo /usr/pandora/scripts/op_gamma.sh %.2f", pandora_gamma);
int dummy = system(buf);
}
}
#endif
static void signal_handler(int sig) {
if (g_xrefresh)
xrefresh();
#ifdef PANDORA
pandora_reset_gamma();
#endif
#ifdef BCMHOST
if (g_bcm_active) {
g_bcm_active = false;
bcm_host_deinit();
}
#endif
#ifndef ANDROID
if (g_stacktrace) {
switch (sig) {
case SIGBUS:
case SIGFPE:
case SIGILL:
case SIGSEGV: {
void *array[10];
size_t size = backtrace(array, 10);
if (! size) {
printf("LIBGL: No stacktrace. Compile with -funwind-tables.\n");
} else {
printf("LIBGL: Stacktrace: %zd\n", size);
backtrace_symbols_fd(array, size, 2);
}
break;
}
}
}
#endif
signal(sig, SIG_DFL);
raise(sig);
}
#ifdef PANDORA
static void init_liveinfo() {
static const char socket_name[] = "\0liveinfo";
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (sock == -1) {
// no socket, so LiveInfo probably not active
return;
}
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
memcpy(sun.sun_path, socket_name, sizeof(socket_name));
// send a test string
const char test_string[] = "gl: fpsinfo";
if (sendto(sock, test_string, strlen(test_string), 0,(struct sockaddr *)&sun, sizeof(sun))<0) {
// error, so probably not present
close(sock);
sock=-1;
} else
fcntl(sock, F_SETFL, O_NONBLOCK);
}
static void fast_math() {
// enable Cortex A8 RunFast
int v = 0;
__asm__ __volatile__ (
"vmrs %0, fpscr\n"
"orr %0, #((1<<25)|(1<<24))\n" // default NaN, flush-to-zero
"vmsr fpscr, %0\n"
//"vmrs %0, fpscr\n"
: "=&r"(v));
}
#endif
extern void initialize_glshim();
extern int initialized;
static void scan_env() {
static bool first = true;
if (! first)
return;
if (! initialized)
{
initialize_glshim();
}
/* Check for some corruption inside state.... */
/*
if ((glstate->texture.active < 0) || (glstate->texture.active > MAX_TEX) ||
(glstate->vao->pointers.vertex.buffer!= 0) || (glstate->vao->vertex != 0) || (glstate->list.active!=0)) {
SHUT(printf("LIBGL: Warning, memory corruption detected at init, trying to compensate\n"));
initialize_glshim();
}
*/
// initialise MapDrawable too
{
int ret;
MapDrawable = kh_init(mapdrawable);
kh_put(mapdrawable, MapDrawable, 1, &ret);
kh_del(mapdrawable, MapDrawable, 1);
}
first = false;
SHUT(printf("LIBGL: built on %s %s\n", __DATE__, __TIME__));
#define env(name, global, message) \
char *env_##name = getenv(#name); \
if (env_##name && strcmp(env_##name, "1") == 0) { \
SHUT(printf("LIBGL: " message "\n")); \
global = true; \
}
env(LIBGL_XREFRESH, g_xrefresh, "xrefresh will be called on cleanup");
env(LIBGL_STACKTRACE, g_stacktrace, "stacktrace will be printed on crash");
// if ok, grab the init/deinit functions
if (bcm_host) {
bcm_host_init = dlsym(bcm_host, "bcm_host_init");
bcm_host_deinit = dlsym(bcm_host, "bcm_host_deinit");
if (bcm_host_init && bcm_host_deinit)
g_bcmhost = true;
}
if (g_xrefresh || g_stacktrace || g_bcmhost) {
// TODO: a bit gross. Maybe look at this: http://stackoverflow.com/a/13290134/293352
signal(SIGBUS, signal_handler);
signal(SIGFPE, signal_handler);
signal(SIGILL, signal_handler);
signal(SIGSEGV, signal_handler);
if (g_xrefresh || g_bcmhost) {
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
}
if (g_xrefresh)
atexit(xrefresh);
#ifndef ANDROID
#ifdef BCMHOST
atexit(bcm_host_deinit);
#endif
#endif //ANDROID
}
env(LIBGL_FB, g_usefb, "framebuffer output enabled");
if (env_LIBGL_FB && strcmp(env_LIBGL_FB, "2") == 0) {
SHUT(printf("LIBGL: using framebuffer + fbo\n"));
g_usefb = true;
g_usefbo = true;
}
env(LIBGL_FPS, g_showfps, "fps counter enabled");
#ifdef USE_FBIO
env(LIBGL_VSYNC, g_vsync, "vsync enabled");
if (g_vsync) {
init_vsync();
}
#endif
#ifdef PANDORA
init_liveinfo();
if (sock>-1) {
SHUT(printf("LIBGL: LiveInfo detected, fps will be shown\n"));
}
#endif
env(LIBGL_RECYCLEFBO, g_recyclefbo, "Recycling of FBO enabled");
// Texture hacks
char *env_mipmap = getenv("LIBGL_MIPMAP");
if (env_mipmap && strcmp(env_mipmap, "1") == 0) {
automipmap = 1;
SHUT(printf("LIBGL: AutoMipMap forced\n"));
}
if (env_mipmap && strcmp(env_mipmap, "2") == 0) {
automipmap = 2;
SHUT(printf("LIBGL: guess AutoMipMap\n"));
}
if (env_mipmap && strcmp(env_mipmap, "3") == 0) {
automipmap = 3;
SHUT(printf("LIBGL: ignore MipMap\n"));
}
if (env_mipmap && strcmp(env_mipmap, "4") == 0) {
automipmap = 4;
SHUT(printf("LIBGL: ignore AutoMipMap on non-squared textures\n"));
}
char *env_texcopy = getenv("LIBGL_TEXCOPY");
if (env_texcopy && strcmp(env_texcopy, "1") == 0) {
texcopydata = 1;
SHUT(printf("LIBGL: Texture copy enabled\n"));
}
char *env_shrink = getenv("LIBGL_SHRINK");
if (env_shrink && strcmp(env_shrink, "1") == 0) {
texshrink = 1;
SHUT(printf("LIBGL: Texture shink, mode 1 selected (everything / 2)\n"));
}
if (env_shrink && strcmp(env_shrink, "2") == 0) {
texshrink = 2;
SHUT(printf("LIBGL: Texture shink, mode 2 selected (only > 512 /2 )\n"));
}
if (env_shrink && strcmp(env_shrink, "3") == 0) {
texshrink = 3;
SHUT(printf("LIBGL: Texture shink, mode 3 selected (only > 256 /2 )\n"));
}
if (env_shrink && strcmp(env_shrink, "4") == 0) {
texshrink = 4;
SHUT(printf("LIBGL: Texture shink, mode 4 selected (only > 256 /2, >=1024 /4 )\n"));
}
if (env_shrink && strcmp(env_shrink, "5") == 0) {
texshrink = 5;
SHUT(printf("LIBGL: Texture shink, mode 5 selected (every > 256 is downscaled to 256 ), but not for empty texture\n"));
}
if (env_shrink && strcmp(env_shrink, "6") == 0) {
texshrink = 6;
SHUT(printf("LIBGL: Texture shink, mode 6 selected (only > 128 /2, >=512 is downscaled to 256 ), but not for empty texture\n"));
}
if (env_shrink && strcmp(env_shrink, "7") == 0) {
texshrink = 7;
SHUT(printf("LIBGL: Texture shink, mode 7 selected (only > 512 /2 ), but not for empty texture\n"));
}
if (env_shrink && strcmp(env_shrink, "8") == 0) {
texshrink = 8;
SHUT(printf("LIBGL: Texture shink, mode 8 selected (advertise 8192 max texture size, but >2048 are shrinked to 2048)\n"));
}
if (env_shrink && strcmp(env_shrink, "9") == 0) {
texshrink = 9;
SHUT(printf("LIBGL: Texture shink, mode 9 selected (advertise 8192 max texture size, but >4096 are quadshrinked and > 512 are shrinked), but not for empty texture\n"));
}
if (env_shrink && strcmp(env_shrink, "10") == 0) {
texshrink = 10;
SHUT(printf("LIBGL: Texture shink, mode 10 selected (advertise 8192 max texture size, but >2048 are quadshrinked and > 512 are shrinked), but not for empty texture\n"));
}
char *env_dump = getenv("LIBGL_TEXDUMP");
if (env_dump && strcmp(env_dump, "1") == 0) {
texdump = 1;
SHUT(printf("LIBGL: Texture dump enabled\n"));
}
char *env_alpha = getenv("LIBGL_ALPHAHACK");
if (env_alpha && strcmp(env_alpha, "1") == 0) {
alphahack = 1;
SHUT(printf("LIBGL: Alpha Hack enabled\n"));
}
#ifdef TEXSTREAM
char *env_stream = getenv("LIBGL_STREAM");
if (env_stream && strcmp(env_stream, "1") == 0) {
texstream = InitStreamingCache();
SHUT(printf("LIBGL: Streaming texture %s\n",(texstream)?"enabled":"not available"));
//FreeStreamed(AddStreamed(1024, 512, 0));
}
if (env_stream && strcmp(env_stream, "2") == 0) {
texstream = InitStreamingCache()?2:0;
SHUT(printf("LIBGL: Streaming texture %s\n",(texstream)?"forced":"not available"));
//FreeStreamed(AddStreamed(1024, 512, 0));
}
#endif
char *env_copy = getenv("LIBGL_COPY");
if (env_copy && strcmp(env_copy, "1") == 0) {
SHUT(printf("LIBGL: No glCopyTexImage2D / glCopyTexSubImage2D hack\n"));
copytex = 1;
}
char *env_lumalpha = getenv("LIBGL_NOLUMALPHA");
if (env_lumalpha && strcmp(env_lumalpha, "1") == 0) {
nolumalpha = 1;
SHUT(printf("LIBGL: GL_LUMINANCE_ALPHA hardware support disabled\n"));
}
env(LIBGL_BLENDHACK, blendhack, "Change Blend GL_SRC_ALPHA, GL_ONE to GL_ONE, GL_ONE");
env(LIBGL_BLENDCOLOR, export_blendcolor, "Export a (faked) glBlendColor");
env(LIBGL_NOERROR, glshim_noerror, "glGetError() always return GL_NOERROR");
env(LIBGL_SILENTSTUB, export_silentstub, "Stub/non present functions are not printed");
char *env_version = getenv("LIBGL_VERSION");
if (env_version) {
SHUT(printf("LIBGL: Overide version string with \"%s\" (should be in the form of \"1.x\")\n", env_version));
}
snprintf(glshim_version, 49, "%s glshim wrapper", (env_version)?env_version:"1.5");
#ifdef PANDORA
char *env_gamma = getenv("LIBGL_GAMMA");
if (env_gamma) {
pandora_gamma=atof(env_gamma);
SHUT(printf("LIBGL: Set gamma to %.2f\n", pandora_gamma));
atexit(pandora_reset_gamma);
}
#endif
char *env_srgb = getenv("LIBGL_SRGB");
if (env_srgb && strcmp(env_srgb, "1") == 0) {
glx_surface_srgb = 1;
SHUT(printf("LIBGL: enabling sRGB support\n"));
}
char *env_fastmath = getenv("LIBGL_FASTMATH");
if (env_fastmath && strcmp(env_fastmath, "1") == 0) {
#ifdef PANDORA
SHUT(printf("LIBGL: Enable FastMath for cortex-a8\n"));
fast_math();
#else
SHUT(printf("LIBGL: No FastMath on this platform\n"));
#endif
}
char *env_npot = getenv("LIBGL_NPOT");
if (env_npot && strcmp(env_npot, "1") == 0) {
glshim_npot = 1;
SHUT(printf("LIBGL: Expose limited NPOT extension\n"));
}
if (env_npot && strcmp(env_npot, "2") == 0) {
glshim_npot = 2;
SHUT(printf("LIBGL: Expose GL_ARB_texture_non_power_of_two extension\n"));
}
char *env_queries = getenv("LIBGL_GLQUERIES");
if (env_queries && strcmp(env_queries, "1") == 0) {
glshim_queries = 1;
SHUT(printf("LIBGL: Expose fake glQueries functions\n"));
}
char cwd[1024];
if (getcwd(cwd, sizeof(cwd))!= NULL)
SHUT(printf("LIBGL: Current folder is:%s\n", cwd));
}
#ifndef ANDROID
EXPORT GLXContext glXCreateContext(Display *display,
XVisualInfo *visual,
GLXContext shareList,
Bool isDirect) {
//printf("glXCreateContext(%p, %p, %p, %i)\n", display, visual, shareList, isDirect);
EGLint configAttribs[] = {
#ifdef PANDORA
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
#endif
EGL_DEPTH_SIZE, 16,
#ifdef USE_ES2
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else
EGL_BUFFER_SIZE, 16,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
EGL_NONE
};
scan_env();
if (g_usefb && fbcontext_count>0) {
// don't create a new context, one FB is enough...
fbcontext_count++;
return fbContext;
}
#ifdef BCMHOST
if (! g_bcm_active) {
g_bcm_active = true;
bcm_host_init();
}
#endif
LOAD_EGL(eglMakeCurrent);
LOAD_EGL(eglDestroyContext);
LOAD_EGL(eglDestroySurface);
LOAD_EGL(eglBindAPI);
LOAD_EGL(eglInitialize);
LOAD_EGL(eglCreateContext);
LOAD_EGL(eglChooseConfig);
LOAD_EGL(eglQueryString);
GLXContext fake = malloc(sizeof(struct __GLXContextRec));
memset(fake, 0, sizeof(struct __GLXContextRec));
fake->glstate = NewGLState((shareList)?shareList->glstate:NULL);
#if 1
if(g_usefb)
fbContext = fake;
#else
if (!g_usefb) {
if (eglDisplay != NULL)
egl_eglMakeCurrent(eglDisplay, NULL, NULL, EGL_NO_CONTEXT); // just in case some context is already attached. *TODO: track that?
} else {
if (eglDisplay != NULL) {
if (eglSurface!=NULL) {
// A surface already exist....
fake->display = g_display;
fake->direct = true;
fake->xid = 1; //TODO: Proper handling of that id...
return fake; // Do nothing
}
egl_eglMakeCurrent(eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
if (eglContext != NULL) {
egl_eglDestroyContext(eglDisplay, eglContext);
eglContext = NULL;
}
if (eglSurface != NULL) {
egl_eglDestroySurface(eglDisplay, eglSurface);
eglSurface = NULL;
}
}
fbContext = fake;
}
#endif
// make an egl context here...
EGLBoolean result;
if (eglDisplay == NULL || eglDisplay == EGL_NO_DISPLAY) {
init_display(display);
if (eglDisplay == EGL_NO_DISPLAY) {
printf("LIBGL: Unable to create EGL display.\n");
return fake;
}
}
// first time?
if (eglInitialized == false) {
egl_eglBindAPI(EGL_OPENGL_ES_API);
result = egl_eglInitialize(eglDisplay, NULL, NULL);
if (result != EGL_TRUE) {
printf("LIBGL: Unable to initialize EGL display.\n");
return fake;
}
eglInitialized = true;
}
// With the display, try to check if sRGB surface are supported
if (glx_surface_srgb==1) {
if(strstr(egl_eglQueryString(eglDisplay, EGL_EXTENSIONS), "EGL_KHR_gl_colorspace")) {
printf("LIBGL: sRGB surface supported\n");
glx_surface_srgb=2; // test only 1 time
} else
glx_surface_srgb=0;
}
int configsFound;
result = egl_eglChooseConfig(eglDisplay, configAttribs, fake->eglConfigs, 1, &configsFound);
if(g_usefb)
eglConfigs[0] = fake->eglConfigs[0];
CheckEGLErrors();
if (result != EGL_TRUE || configsFound == 0) {
printf("LIBGL: No EGL configs found.\n");
return fake;
}
EGLContext shared = (shareList)?shareList->eglContext:EGL_NO_CONTEXT;
fake->eglContext = egl_eglCreateContext(eglDisplay, fake->eglConfigs[0], shared, egl_context_attrib);
if(g_usefb)
eglContext = fake->eglContext;
CheckEGLErrors();
// need to return a glx context pointing at it
fake->display = (g_usefb)?g_display:display;
fake->direct = true;
fake->xid = 1; //TODO: Proper handling of that id...
fake->contextType = 0; //Window
/*
// why unassign the context, it's not assigned yet
if (!g_usefb) {
// unassign the context, it's not supposed to be active at the creation
egl_eglMakeCurrent(eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
}
*/
return fake;
}
GLXContext createPBufferContext(Display *display, GLXContext shareList, GLXFBConfig config) {
EGLint configAttribs[] = {
EGL_RED_SIZE, (config)?config->redBits:0,
EGL_GREEN_SIZE, (config)?config->greenBits:0,
EGL_BLUE_SIZE, (config)?config->blueBits:0,
EGL_ALPHA_SIZE, (config)?config->alphaBits:0,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
EGL_NONE
};
LOAD_EGL(eglBindAPI);
LOAD_EGL(eglInitialize);
LOAD_EGL(eglChooseConfig);
LOAD_EGL(eglCreateContext);
// Check that the config is for PBuffer
if(config->drawableType&GLX_PBUFFER_BIT!=GLX_PBUFFER_BIT)
return 0;
// Init what need to be done
EGLBoolean result;
if (eglDisplay == NULL || eglDisplay == EGL_NO_DISPLAY) {
init_display(display);
if (eglDisplay == EGL_NO_DISPLAY) {
printf("LIBGL: Unable to create EGL display.\n");
return 0;
}
}
// first time?
if (eglInitialized == false) {
egl_eglBindAPI(EGL_OPENGL_ES_API);
result = egl_eglInitialize(eglDisplay, NULL, NULL);
if (result != EGL_TRUE) {
printf("LIBGL: Unable to initialize EGL display.\n");
return 0;
}
eglInitialized = true;
}
// select a configuration
int configsFound;
static EGLConfig pbufConfigs[1];
result = egl_eglChooseConfig(eglDisplay, configAttribs, pbufConfigs, 1, &configsFound);
CheckEGLErrors();
if (result != EGL_TRUE || configsFound == 0) {
printf("LIBGL: No EGL configs found.\n");
return 0;
}
EGLContext shared = (shareList)?shareList->eglContext:EGL_NO_CONTEXT;
GLXContext fake = malloc(sizeof(struct __GLXContextRec));
memset(fake, 0, sizeof(struct __GLXContextRec));
fake->glstate = NewGLState((shareList)?shareList->glstate:NULL);
fake->eglContext = egl_eglCreateContext(eglDisplay, fake->eglConfigs[0], shared, egl_context_attrib);
CheckEGLErrors();
// need to return a glx context pointing at it
fake->display = (g_usefb)?g_display:display;
fake->direct = true;
fake->xid = 1; //TODO: Proper handling of that id...
fake->contextType = 1; //PBuffer
return fake;
}
EXPORT GLXContext glXCreateContextAttribsARB(Display *display, GLXFBConfig config,
GLXContext share_context, Bool direct,
const int *attrib_list) {
if(config && config->drawableType==GLX_PBUFFER_BIT) {
return createPBufferContext(display, share_context, config);
} else
return glXCreateContext(display, NULL, share_context, direct);
}
EXPORT void glXDestroyContext(Display *display, GLXContext ctx) {
//printf("glXDestroyContext(%p, %p)\n", display, ctx);
if (g_usefb && ctx->contextType==0) {
if (fbcontext_count==0)
return; // Should not happens!
if (--fbcontext_count > 0)
return; // Nothing to do...
}
if ((!g_usefb && ctx->eglContext) || (g_usefb && eglContext)) {
if (g_usefbo && ctx->contextType==0) {
deleteMainFBO();
}
DeleteGLState(ctx->glstate);
LOAD_EGL(eglDestroyContext);
LOAD_EGL(eglDestroySurface);
EGLBoolean result = egl_eglDestroyContext(eglDisplay, ctx->eglContext);
ctx->eglContext = 0;
if (ctx->eglSurface != 0) {
egl_eglDestroySurface(eglDisplay, ctx->eglSurface);
ctx->eglSurface = 0;
}
if(g_usefb && ctx->contextType==0) {
// clean global eglFB too
eglSurface = 0;
eglContext = 0;
}
if (result != EGL_TRUE) {
printf("LIBGL: Failed to destroy EGL context.\n");
}
/*if (fbdev >= 0) {
close(fbdev);
fbdev = -1;
}*/
}
if (g_usefb)
fbContext = NULL;
return;
}
EXPORT Display *glXGetCurrentDisplay() {
if (!g_usefb)
return XOpenDisplay(NULL);
else
if (g_display && eglContext) {
return g_display;
}
return XOpenDisplay(NULL);
}
EXPORT XVisualInfo *glXChooseVisual(Display *display,
int screen,
int *attributes) {
// apparently can't trust the Display I'm passed?
/*
if (g_display == NULL) {
g_display = XOpenDisplay(NULL);
}
*/
glx_default_depth = XDefaultDepth(display, screen);
if (glx_default_depth != 16 && glx_default_depth != 24 && glx_default_depth != 32)
printf("LIBGL: unusual desktop color depth %d\n", glx_default_depth);
XVisualInfo *visual = (XVisualInfo *)malloc(sizeof(XVisualInfo));
if (!XMatchVisualInfo(display, screen, glx_default_depth, TrueColor, visual)) {
printf("LIBGL: XMatchVisualInfo failed in glXChooseVisual\n");
return NULL;
}
return visual;
}
/*
EGL_BAD_MATCH is generated if draw or read are not compatible with context
or if context is set to EGL_NO_CONTEXT and draw or read are not set to
EGL_NO_SURFACE, or if draw or read are set to EGL_NO_SURFACE and context is
not set to EGL_NO_CONTEXT.
*/
EXPORT Bool glXMakeCurrent(Display *display,
GLXDrawable drawable,
GLXContext context) {
//printf("glXMakeCurrent(%p, %p, %p)\n", display, drawable, context);
LOAD_EGL(eglMakeCurrent);
LOAD_EGL(eglDestroySurface);
LOAD_EGL(eglCreateWindowSurface);
LOAD_EGL(eglQuerySurface);
int created = (context)?isPBuffer(drawable):0;
EGLint const sRGB[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE};
#if 1
EGLContext eglContext = EGL_NO_CONTEXT;
EGLSurface eglSurf = 0;
EGLConfig eglConfig = 0;
if(context) {
eglContext = context->eglContext;
if(context->drawable==drawable && context->eglSurface)
// same-same, recycling...
eglSurf = context->eglSurface;
else {
// new one
if(created) {
eglSurf = context->eglSurface = (EGLSurface)drawable;
context->eglContext = eglContext = pbuffersize[created-1].Context; // this context is ok for the PBuffer
} else {
if(g_usefb) {
if(eglSurface)
eglSurf = context->eglSurface = eglSurface;
else
eglSurface = eglSurf = context->eglSurface = egl_eglCreateWindowSurface(eglDisplay, context->eglConfigs[0], 0, (glx_surface_srgb)?sRGB:NULL);
} else {
if(context->eglSurface)
egl_eglDestroySurface(eglDisplay, context->eglSurface);
eglSurf = context->eglSurface = egl_eglCreateWindowSurface(eglDisplay, context->eglConfigs[0], drawable, (glx_surface_srgb)?sRGB:NULL);
}
}
}
eglConfig = context->eglConfigs[0];
}
glxContext = context;
EGLBoolean result = egl_eglMakeCurrent(eglDisplay, eglSurf, eglSurf, eglContext);
#else
if (eglDisplay != NULL) {
if (!g_usefb)
egl_eglMakeCurrent(eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
else {
if (!context) {
egl_eglMakeCurrent(eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
if (eglSurface != NULL) {
egl_eglDestroySurface(eglDisplay, eglSurface);
eglSurface = NULL;
}
}
}
}
glxContext = context;
// call with NULL to just destroy old stuff.
if (! context) {
return true;
}
if (eglDisplay == NULL) {
init_display(display);
}
if (g_usefb)
drawable = 0;
EGLBoolean result;
created = 1;
if (!g_usefb) {
// need current surface for eglSwapBuffer
eglContext = context->eglContext;
// if surface on a different drawable exist, destroy it first
if ((context->drawable != drawable) && (context->eglSurface)) {
egl_eglDestroySurface(eglDisplay, context->eglSurface);
context->eglSurface = NULL;
}
// Now get the Surface
if (context->eglSurface)
eglSurface = context->eglSurface; // reused previously created Surface
else {
eglSurface = context->eglSurface = egl_eglCreateWindowSurface(eglDisplay, context->eglConfigs[0], drawable, (glx_surface_srgb)?sRGB:NULL);
}
result = egl_eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
} else {
if (!eglSurface) {
eglSurface = egl_eglCreateWindowSurface(eglDisplay, eglConfigs[0], drawable, (glx_surface_srgb)?sRGB:NULL); // create surface only if needed
result = egl_eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
} else
result = EGL_TRUE;
}
#endif
CheckEGLErrors();
{
// update MapDrawable
int ret;
khint_t k = kh_get(mapdrawable, MapDrawable, drawable);
map_drawable_t* map = NULL;
if (k == kh_end(MapDrawable)){
k = kh_put(mapdrawable, MapDrawable, drawable, &ret);
map = kh_value(MapDrawable, k) = (map_drawable_t*)malloc(sizeof(map_drawable_t));
map->drawable = drawable;
} else {
map = kh_value(MapDrawable, k);
}
map->surface = eglSurf;
map->PBuffer = created;
}
if (context) {
context->drawable = drawable;
ActivateGLState(context->glstate);
#ifdef PANDORA
if(created) pandora_set_gamma();
#endif
CheckEGLErrors();
if (result) {
if (g_usefbo && created) {
// get size of the surface...
egl_eglQuerySurface(eglDisplay,eglSurf,EGL_WIDTH,&g_width);
egl_eglQuerySurface(eglDisplay,eglSurf,EGL_HEIGHT,&g_height);
// create the main_fbo...
printf("LIBGL: Create FBO of %ix%i 32bits\n", g_width, g_height);
createMainFBO(g_width, g_height);
}
// finished
return true;
}
return false;
}
return true;
}
EXPORT Bool glXMakeContextCurrent(Display *display, int drawable,
int readable, GLXContext context) {
return glXMakeCurrent(display, drawable, context);
}
EXPORT void glXSwapBuffers(Display *display,
int drawable) {
static int frames = 0;
LOAD_EGL(eglSwapBuffers);
// TODO: what if active context is not on the drawable?
int old_batch = glstate->gl_batch;
if (glstate->gl_batch || glstate->list.active){
flush();
}
EGLSurface surface = eglSurface;
int PBuffer = 0;
{
// get MapDrawable surface
khint_t k = kh_get(mapdrawable, MapDrawable, drawable);
map_drawable_t* map = NULL;
if (k != kh_end(MapDrawable)){
map = kh_value(MapDrawable, k);
surface = map->surface;
PBuffer = map->PBuffer;
}
}
#ifdef USE_FBIO
if (g_vsync && fbdev >= 0 && PBuffer==0) {
// TODO: can I just return if I don't meet vsync over multiple frames?
// this will just block otherwise.
int arg = 0;
for (int i = 0; i < swap_interval; i++) {
ioctl(fbdev, FBIO_WAITFORVSYNC, &arg);
}
}
#endif
if (g_usefbo && PBuffer==0) {
glstate->gl_batch = 0;
unbindMainFBO();
blitMainFBO();
// blit the main_fbo before swap
}
egl_eglSwapBuffers(eglDisplay, surface);
CheckEGLErrors();
#ifdef PANDORA
if (g_showfps || (sock>-1)) {
// framerate counter
static float avg, fps = 0;
static int frame1, last_frame, frame, now, current_frames;
struct timeval out;
gettimeofday(&out, NULL);
now = out.tv_sec;
frame++;
current_frames++;
if (frame == 1) {
frame1 = now;
} else if (frame1 < now) {
if (last_frame < now) {
float change = current_frames / (float)(now - last_frame);
float weight = 0.7;
if (! fps) {
fps = change;
} else {
fps = (1 - weight) * fps + weight * change;
}
current_frames = 0;
avg = frame / (float)(now - frame1);
if (g_showfps) printf("LIBGL: fps: %.2f, avg: %.2f\n", fps, avg);
if (sock>-1) {
char tmp[60];
snprintf(tmp, 60, "gl: %2.2f", fps);
sendto(sock, tmp, strlen(tmp), 0,(struct sockaddr *)&sun, sizeof(sun));
}
}
}
last_frame = now;
}
#endif
if (g_usefbo && PBuffer==0) {
glstate->gl_batch = old_batch;
bindMainFBO();
}
}
EXPORT int glXGetConfig(Display *display,
XVisualInfo *visual,
int attribute,
int *value) {
return get_config_default(display, attribute, value);
}
EXPORT const char *glXQueryExtensionsString(Display *display, int screen) {
const char *extensions = {
"GLX_ARB_create_context "
"GLX_ARB_create_context_profile "
"GLX_EXT_create_context_es2_profile "
"GLX_ARB_get_proc_address "
};
return extensions;
}
EXPORT const char *glXQueryServerString(Display *display, int screen, int name) {
return "";
}
EXPORT Bool glXQueryExtension(Display *display, int *errorBase, int *eventBase) {
if (errorBase)
*errorBase = 0;
if (eventBase)
*eventBase = 0;
return true;
}
EXPORT Bool glXQueryVersion(Display *display, int *major, int *minor) {
// TODO: figure out which version we want to pretend to implement
*major = 1;
*minor = 4;
return true;
}
EXPORT const char *glXGetClientString(Display *display, int name) {
// TODO: return actual data here
switch (name) {
case GLX_VENDOR: return "ptitSeb";
case GLX_VERSION: return "1.4 OpenPandora";
case GLX_EXTENSIONS: break;
}
return "";
}
EXPORT int glXQueryContext( Display *dpy, GLXContext ctx, int attribute, int *value ){
*value=0;
if (ctx) switch (attribute) {
case GLX_FBCONFIG_ID: *value=ctx->xid; break;
case GLX_RENDER_TYPE: *value=GLX_RGBA_TYPE; break;
case GLX_SCREEN: break; // screen n# is always 0
}
return 0;
}
/*
EXPORT void glXQueryDrawable( Display *dpy, int draw, int attribute,
unsigned int *value ) {
*value=0;
}
*/
// stubs for glfw (GLX 1.3)
EXPORT GLXContext glXGetCurrentContext() {
// hack to make some games start
if (g_usefb)
return glxContext ? glxContext : fbContext;
else
return glxContext;
}
EXPORT GLXFBConfig *glXChooseFBConfig(Display *display, int screen,
const int *attrib_list, int *count) {
//printf("glXChooseFBConfig(%p, %d, %p, %p)\n", display, screen, attrib_list, count);
*count = 1;
GLXFBConfig *configs = (GLXFBConfig *)malloc(sizeof(GLXFBConfig) + sizeof(struct __GLXFBConfigRec));
configs[0] = (GLXFBConfig)((char*)(&configs[0])+sizeof(GLXFBConfig));
memset(configs[0], 0, sizeof(struct __GLXFBConfigRec));
// fill that config with some of the attrib_list info...
configs[0]->drawableType = GLX_WINDOW_BIT | GLX_PBUFFER_BIT;
configs[0]->screen = 0;
configs[0]->maxPbufferWidth = configs[0]->maxPbufferHeight = 2048;
configs[0]->redBits = configs[0]->greenBits = configs[0]->blueBits = configs[0]->alphaBits = 0;
if(attrib_list) {
int i = 0;
while(attrib_list[i]!=0) {
switch(attrib_list[i++]) {
case GLX_RED_SIZE:
configs[0]->redBits = attrib_list[i++];
if(configs[0]->redBits==GLX_DONT_CARE) configs[0]->redBits = 0;
break;
case GLX_GREEN_SIZE:
configs[0]->greenBits = attrib_list[i++];
if(configs[0]->greenBits==GLX_DONT_CARE) configs[0]->greenBits = 0;
break;
case GLX_BLUE_SIZE:
configs[0]->blueBits = attrib_list[i++];
if(configs[0]->blueBits==GLX_DONT_CARE) configs[0]->blueBits = 0;
break;
case GLX_ALPHA_SIZE:
configs[0]->alphaBits = attrib_list[i++];
if(configs[0]->alphaBits==GLX_DONT_CARE) configs[0]->alphaBits = 0;
break;
case GLX_DRAWABLE_TYPE:
configs[0]->drawableType = attrib_list[i++];
break;
// discard other stuffs
}
}
}
return configs;
}
EXPORT GLXFBConfig *glXChooseFBConfigSGIX(Display *display, int screen,
const int *attrib_list, int *count) {
return glXChooseFBConfig(display, screen, attrib_list, count);
}
EXPORT GLXFBConfig *glXGetFBConfigs(Display *display, int screen, int *count) {
//printf("glXGetFBConfigs(%p, %d, %p)\n", display, screen, count);
*count = 1;
// this is to only do 1 malloc instead of 1 for the array and one for the element...
GLXFBConfig *configs = (GLXFBConfig *)malloc(sizeof(GLXFBConfig) + sizeof(struct __GLXFBConfigRec));
configs[0] = (GLXFBConfig)((char*)(&configs[0])+sizeof(GLXFBConfig));
memset(configs[0], 0, sizeof(struct __GLXFBConfigRec));
configs[0]->drawableType = GLX_WINDOW_BIT | GLX_PBUFFER_BIT;
configs[0]->redBits = configs[0]->greenBits = configs[0]->blueBits = configs[0]->alphaBits = 8;
return configs;
}
EXPORT int glXGetFBConfigAttrib(Display *display, GLXFBConfig config, int attribute, int *value) {
//printf("glXGetFBConfigAttrib(%p, %p, 0x%04X, %p)\n", display, config, attribute, value);
return get_config_default(display, attribute, value);
}
EXPORT XVisualInfo *glXGetVisualFromFBConfig(Display *display, GLXFBConfig config) {
//printf("glXGetVisualFromFBConfig(%p, %p)\n", display, config);
/*if (g_display == NULL) {
g_display = XOpenDisplay(NULL);
}*/
if (glx_default_depth==0)
glx_default_depth = XDefaultDepth(display, 0);
XVisualInfo *visual = (XVisualInfo *)malloc(sizeof(XVisualInfo));
XMatchVisualInfo(display, 0, glx_default_depth, TrueColor, visual);
return visual;
}
EXPORT GLXContext glXCreateNewContext(Display *display, GLXFBConfig config,
int render_type, GLXContext share_list,
Bool is_direct) {
//printf("glXCreateNewContext(%p, %p, %d, %p, %i), drawableType=0x%02X\n", display, config, render_type, share_list, is_direct, (config)?config->drawableType:0);
if(config && config->drawableType==GLX_PBUFFER_BIT) {
return createPBufferContext(display, share_list, config);
} else
return glXCreateContext(display, 0, share_list, is_direct);
}
#endif //ANDROID
EXPORT void glXSwapIntervalMESA(int interval) {
//printf("glXSwapInterval(%i)\n", interval);
#ifdef USE_FBIO
if (! g_vsync)
printf("LIBGL: Enable LIBGL_VSYNC=1 if you want to use vsync.\n");
swap_interval = interval;
#else
LOAD_EGL(eglSwapInterval);
egl_eglSwapInterval(eglDisplay, swap_interval);
#endif
}
EXPORT void glXSwapIntervalSGI(int interval) {
glXSwapIntervalMESA(interval);
}
#ifndef ANDROID
EXPORT void glXSwapIntervalEXT(Display *display, int drawable, int interval) {
glXSwapIntervalMESA(interval);
}
// misc stubs
EXPORT void glXCopyContext(Display *display, GLXContext src, GLXContext dst, GLuint mask) {
// mask is ignored for now, but should include glPushAttrib / glPopAttrib
memcpy(dst, src, sizeof(struct __GLXContextRec));
}
EXPORT void glXCreateGLXPixmap(Display *display, XVisualInfo * visual, Pixmap pixmap) {} // should return GLXPixmap
EXPORT void glXDestroyGLXPixmap(Display *display, void *pixmap) {} // really wants a GLXpixmap
EXPORT Window glXCreateWindow(Display *display, GLXFBConfig config, Window win, int *attrib_list) {return win;} // should return GLXWindow
EXPORT void glXDestroyWindow(Display *display, void *win) {} // really wants a GLXWindow
EXPORT GLXDrawable glXGetCurrentDrawable() {
if (glxContext)
return glxContext->drawable;
else
return 0;
} // this should actually return GLXDrawable.
EXPORT Bool glXIsDirect(Display * display, GLXContext ctx) {
return true;
}
EXPORT void glXUseXFont(Font font, int first, int count, int listBase) {
/* Mostly from MesaGL-9.0.1
*
*/
// First get current Display and Window
XFontStruct *fs;
unsigned int max_width, max_height, max_bm_width, max_bm_height;
Pixmap pixmap;
XGCValues values;
GC gc;
int i;
unsigned long valuemask;
GLubyte *bm;
Display *dpy;
Window win;
if (g_usefb) {
dpy = g_display;
win = RootWindow(dpy, XDefaultScreen(dpy));
} else {
dpy = glxContext->display;
win = glxContext->drawable; //TODO, check that drawable is a window and not a pixmap ?
}
// Grab font params
fs = XQueryFont(dpy, font);
if (!fs) {
printf("LIBGL: error, no font set before call to glXUseFont\n");
return;
}
max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
max_bm_width = (max_width + 7) / 8;
max_bm_height = max_height;
bm = (GLubyte *)malloc((max_bm_width * max_bm_height) * sizeof(GLubyte));
if (!bm) {
XFreeFontInfo(NULL, fs, 1);
return;
}
// Save GL texture parameters
GLint swapbytes, lsbfirst, rowlength;
GLint skiprows, skippixels, alignment;
glshim_glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
glshim_glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
glshim_glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
glshim_glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
glshim_glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
glshim_glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
// Set Safe Texture params
glshim_glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
glshim_glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
glshim_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glshim_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glshim_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glshim_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Create GC and Pixmap
pixmap = XCreatePixmap(dpy, win, 10, 10, 1);
values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
values.background = WhitePixel(dpy, DefaultScreen(dpy));
values.font = fs->fid;
valuemask = GCForeground | GCBackground | GCFont;
gc = XCreateGC(dpy, pixmap, valuemask, &values);
XFreePixmap(dpy, pixmap);
// Loop each chars
for (i = 0; i < count; i++) {
unsigned int width, height, bm_width, bm_height;
GLfloat x0, y0, dx, dy;
XCharStruct *ch;
int x, y;
unsigned int c = first + i;
int list = listBase + i;
int valid;
/* check on index validity and get the bounds */
ch = isvalid(fs, c);
if (!ch) {
ch = &fs->max_bounds;
valid = 0;
}
else {
valid = 1;
}
/* glBitmap()' parameters:
straight from the glXUseXFont(3) manpage. */
width = ch->rbearing - ch->lbearing;
height = ch->ascent + ch->descent;
x0 = -ch->lbearing;
y0 = ch->descent - 1;
dx = ch->width;
dy = 0;
/* X11's starting point. */
x = -ch->lbearing;
y = ch->ascent;
/* Round the width to a multiple of eight. We will use this also
for the pixmap for capturing the X11 font. This is slightly
inefficient, but it makes the OpenGL part real easy. */
bm_width = (width + 7) / 8;
bm_height = height;
glshim_glNewList(list, GL_COMPILE);
if (valid && (bm_width > 0) && (bm_height > 0)) {
memset(bm, '\0', bm_width * bm_height);
fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm);
glshim_glBitmap(width, height, x0, y0, dx, dy, bm);
}
else {
glshim_glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
}
glshim_glEndList();
}
// Free GC & Pixmap
free(bm);
XFreeFontInfo(NULL, fs, 1);
XFreeGC(dpy, gc);
// Restore saved packing modes.
glshim_glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
glshim_glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
glshim_glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
glshim_glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
glshim_glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
glshim_glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
// All done
}
#endif //ANDROID
EXPORT void glXWaitGL() {}
EXPORT void glXWaitX() {}
EXPORT void glXReleaseBuffersMESA() {}
#ifndef ANDROID
/* TODO proper implementation */
EXPORT int glXQueryDrawable(Display *dpy, GLXDrawable draw, int attribute, unsigned int *value) {
int pbuf=isPBuffer(draw);
*value = 0;
switch(attribute) {
case GLX_WIDTH:
*value = (pbuf)?pbuffersize[pbuf-1].Width:800;
return 1;
case GLX_HEIGHT:
*value = (pbuf)?pbuffersize[pbuf-1].Height:480;
return 1;
case GLX_PRESERVED_CONTENTS:
return 0;
case GLX_LARGEST_PBUFFER:
return 0;
case GLX_FBCONFIG_ID:
*value = 1;
return 1;
}
return 0;
}
GLXPbuffer addPBuffer(EGLSurface surface, int Width, int Height, EGLContext Context)
{
if(pbufferlist_cap<=pbufferlist_size) {
pbufferlist_cap += 4;
pbufferlist = (GLXPbuffer*)realloc(pbufferlist, sizeof(GLXPbuffer)*pbufferlist_cap);
pbuffersize = (glx_buffSize*)realloc(pbuffersize, sizeof(glx_buffSize)*pbufferlist_cap);
}
pbufferlist[pbufferlist_size] = (GLXPbuffer)surface;
pbuffersize[pbufferlist_size].Width = Width;
pbuffersize[pbufferlist_size].Height = Height;
pbuffersize[pbufferlist_size].Context = Context;
return pbufferlist[pbufferlist_size++];
}
void delPBuffer(int j)
{
LOAD_EGL(eglDestroyContext);
pbufferlist[j] = 0;
pbuffersize[j].Width = 0;
pbuffersize[j].Height = 0;
egl_eglDestroyContext(eglDisplay, pbuffersize[j].Context);
// should pack, but I think it's useless for common use
}
EXPORT void glXDestroyPbuffer(Display * dpy, GLXPbuffer pbuf) {
// printf("LIBGL: Warning, stub glxDestroyPBuffer called\n");
LOAD_EGL(eglDestroySurface);
int j=0;
while(j<pbufferlist_size || pbufferlist[j]==pbuf) j++;
if(j==pbufferlist_size)
return;
// delete de Surface
EGLSurface surface = (EGLSurface)pbufferlist[j];
egl_eglDestroySurface(dpy, surface);
delPBuffer(j);
}
int createPBuffer(Display * dpy, GLXFBConfig config, const EGLint * egl_attribs, EGLSurface* Surface, EGLContext* Context) {
LOAD_EGL(eglChooseConfig);
LOAD_EGL(eglCreatePbufferSurface);
LOAD_EGL(eglInitialize);
LOAD_EGL(eglBindAPI);
LOAD_EGL(eglCreateContext);
EGLint configAttribs[] = {
EGL_RED_SIZE, (config)?config->redBits:0,
EGL_GREEN_SIZE, (config)?config->greenBits:0,
EGL_BLUE_SIZE, (config)?config->blueBits:0,
EGL_ALPHA_SIZE, (config)?config->alphaBits:0,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
EGL_NONE
};
// Check that the config is for PBuffer
if(config->drawableType&GLX_PBUFFER_BIT!=GLX_PBUFFER_BIT)
return 0;
// Init what need to be done
EGLBoolean result;
if (eglDisplay == NULL || eglDisplay == EGL_NO_DISPLAY) {
init_display(dpy);
if (eglDisplay == EGL_NO_DISPLAY) {
printf("LIBGL: Unable to create EGL display.\n");
return 0;
}
}
// first time?
if (eglInitialized == false) {
egl_eglBindAPI(EGL_OPENGL_ES_API);
result = egl_eglInitialize(eglDisplay, NULL, NULL);
if (result != EGL_TRUE) {
printf("LIBGL: Unable to initialize EGL display.\n");
return 0;
}
eglInitialized = true;
}
// select a configuration
int configsFound;
static EGLConfig pbufConfigs[1];
result = egl_eglChooseConfig(eglDisplay, configAttribs, pbufConfigs, 1, &configsFound);
CheckEGLErrors();
if (result != EGL_TRUE || configsFound == 0) {
printf("LIBGL: No EGL configs found.\n");
return 0;
}
// now, create the PBufferSurface
(*Surface) = egl_eglCreatePbufferSurface(eglDisplay, pbufConfigs[0], egl_attribs);
if((*Surface)==EGL_NO_SURFACE) {
printf("LIBGL: Error creating PBuffer\n");
return 0;
}
(*Context) = egl_eglCreateContext(eglDisplay, pbufConfigs[0], EGL_NO_CONTEXT, egl_context_attrib);
return 1;
}
EXPORT GLXPbuffer glXCreatePbuffer(Display * dpy, GLXFBConfig config, const int * attrib_list) {
//printf("glXCreatePbuffer(%p, %p, %p)\n", dpy, config, attrib_list);
LOAD_EGL(eglQuerySurface);
EGLSurface Surface = 0;
EGLContext Context = 0;
//let's create a PBuffer attributes
EGLint egl_attribs[128]; // should be enough
int i = 0;
if(attrib_list) {
int j = 0;
while(attrib_list[j]!=0) {
switch(attrib_list[j++]) {
case GLX_PBUFFER_WIDTH:
egl_attribs[i++] = EGL_WIDTH;
egl_attribs[i++] = attrib_list[j++];
break;
case GLX_PBUFFER_HEIGHT:
egl_attribs[i++] = EGL_HEIGHT;
egl_attribs[i++] = attrib_list[j++];
break;
case GLX_LARGEST_PBUFFER:
egl_attribs[i++] = EGL_LARGEST_PBUFFER;
egl_attribs[i++] = (attrib_list[j++])?EGL_TRUE:EGL_FALSE;
break;
case GLX_PRESERVED_CONTENTS:
j++;
// ignore this one
break;
//nothing, ignore unknown attribs
}
}
}
egl_attribs[i++] = EGL_NONE;
if(createPBuffer(dpy, config, egl_attribs, &Surface, &Context)==0) {
return 0;
}
int Width, Height;
egl_eglQuerySurface(eglDisplay,Surface,EGL_WIDTH,&Width);
egl_eglQuerySurface(eglDisplay,Surface,EGL_HEIGHT,&Height);
return addPBuffer(Surface, Width, Height, Context);
}
#endif //ANDROID