diff options
author | Thorvald Natvig <slicer@users.sourceforge.net> | 2010-01-25 18:46:23 +0300 |
---|---|---|
committer | Thorvald Natvig <slicer@users.sourceforge.net> | 2010-01-25 18:46:23 +0300 |
commit | c00b9bfe9e20869e1acc92651ee8dafaa15479e7 (patch) | |
tree | 5b75d945dd594272fbd8670b88387f1c9eb28489 /overlay_gl | |
parent | eaf4fc0821e811d3194b2809ef548032b858356c (diff) |
Socket-based linux overlay
Diffstat (limited to 'overlay_gl')
-rw-r--r-- | overlay_gl/overlay.c | 427 |
1 files changed, 245 insertions, 182 deletions
diff --git a/overlay_gl/overlay.c b/overlay_gl/overlay.c index d05d9b5ee..fb8f6bbb3 100644 --- a/overlay_gl/overlay.c +++ b/overlay_gl/overlay.c @@ -44,11 +44,15 @@ #include <sys/mman.h> #include <sys/ipc.h> #include <sys/time.h> +#include <sys/socket.h> +#include <sys/un.h> #include <time.h> #include <semaphore.h> #include <fcntl.h> #include <stdarg.h> +#include <pwd.h> #include <math.h> +#include <errno.h> typedef unsigned char bool; #define true 1 @@ -57,12 +61,8 @@ typedef unsigned char bool; #include "../overlay/overlay.h" // Prototypes -static void resolveSM(); static void ods(const char *format, ...); -static struct SharedMem *sm = NULL; -static sem_t *sem = NULL; - static bool bDebug; typedef struct _Context { @@ -70,11 +70,20 @@ typedef struct _Context { Display *dpy; GLXDrawable draw; + unsigned int uiWidth, uiHeight; + unsigned int uiLeft, uiRight, uiTop, uiBottom; + + struct sockaddr_un saName; + int iSocket; + struct OverlayMsg omMsg; + GLuint texture; + + unsigned char *a_ucTexture; + unsigned int uiMappedLength; + bool bValid; bool bGlx; - GLuint textures[NUM_TEXTS]; - unsigned int uiCounter[NUM_TEXTS]; GLuint uiProgram; } Context; @@ -82,13 +91,12 @@ static const char vshader[] = "" "void main() {" "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" "gl_TexCoord[0] = gl_MultiTexCoord0;" - "gl_FrontColor = gl_Color;" "}"; static const char fshader[] = "" "uniform sampler2D tex;" "void main() {" - "gl_FragColor = gl_Color * texture2D(tex, gl_TexCoord[0].st);" + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st);" "}"; const GLfloat fBorder[] = {0.125f, 0.250f, 0.5f, 0.75f}; @@ -107,7 +115,7 @@ FDEF(glXGetProcAddress); static void resolveOpenGL() { RESOLVE(glXSwapBuffers); - + if (! oglXSwapBuffers) { void *lib = dlopen("libGL.so.1", RTLD_GLOBAL | RTLD_NOLOAD); if (! lib) @@ -116,70 +124,19 @@ static void resolveOpenGL() { if (! oglXSwapBuffers) dlclose(lib); } - + RESOLVE(glXGetProcAddressARB); RESOLVE(glXGetProcAddress); } -static void resolveSM() { - static bool warned_sm = false; - static bool warned_ver = false; - - char memname[256]; - char semname[256]; - snprintf(memname, 256, "/MumbleOverlayMem.%d", getuid()); - snprintf(semname, 256, "/MumbleOverlaySem.%d", getuid()); - - int fd = shm_open(memname, O_RDWR, 0600); - if (fd >= 0) { - sm = (struct SharedMem *)(mmap(NULL, sizeof(struct SharedMem), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); - if (sm == (void *)(-1)) { - sm = NULL; - close(fd); - } else { - if ((sm->version[0] != OVERLAY_VERSION_MAJ) || - (sm->version[1] != OVERLAY_VERSION_MIN) || - (sm->version[2] != OVERLAY_VERSION_PATCH)) { - if (! warned_ver) { - fflush(stderr); - fprintf(stderr, "MUMBLE OVERLAY:: Version mismatch. Library is %u.%u.%u.%u, application is %u.%u.%u.%u\n", - OVERLAY_VERSION_MAJ, OVERLAY_VERSION_MIN, OVERLAY_VERSION_PATCH, OVERLAY_VERSION_SUB, - sm->version[0], sm->version[1], sm->version[2], sm->version[3] - ); - fflush(stderr); - warned_ver = true; - } - munmap(sm, sizeof(struct SharedMem)); - sm = NULL; - close(fd); - } else { - sem = sem_open(semname, 0); - if (sem == SEM_FAILED) { - munmap(sm, sizeof(struct SharedMem)); - sm = NULL; - close(fd); - } - } - } - } - - if (sm == NULL) { - if (! warned_sm && ! warned_ver) { - fflush(stderr); - fprintf(stderr, "MUMBLE OVERLAY:: NO CONTACT WITH MUMBLE\n"); - fflush(stderr); - warned_sm = true; - } - } -} - __attribute__((format(printf, 1, 2))) static void ods(const char *format, ...) { if (!bDebug) { - if (! sm || !sm->bDebug) - return; + return; } + fprintf(stderr, "MumbleOverlay: "); + va_list args; va_start(args, format); vfprintf(stderr, format, args); @@ -191,12 +148,21 @@ static void ods(const char *format, ...) { static void newContext(Context * ctx) { int i; - if (sm) { - sm->bHooked = true; + ctx->iSocket = -1; + ctx->omMsg.omh.iLength = -1; + ctx->texture = ~0; + + char *home = getenv("HOME"); + if (home == NULL) { + struct passwd *pwent= getpwuid(getuid()); + if (pwent && pwent->pw_dir && pwent->pw_dir[0]) + home = pwent->pw_dir; } - for (i = 0; i < NUM_TEXTS; i++) { - ctx->uiCounter[i] = 0; - ctx->textures[i] = -1; + + if (home) { + ctx->saName.sun_family = PF_UNIX; + strcpy(ctx->saName.sun_path, home); + strcat(ctx->saName.sun_path, "/.MumbleOverlayPipe"); } ods("OpenGL Version %s, Vendor %s, Renderer %s, Shader %s", glGetString(GL_VERSION), glGetString(GL_VENDOR), glGetString(GL_RENDERER), glGetString(GL_SHADING_LANGUAGE_VERSION)); @@ -221,133 +187,236 @@ static void newContext(Context * ctx) { glLinkProgram(ctx->uiProgram); } -static void drawOverlay(Context *ctx, int width, int height) { - // DEBUG - // sm->bDebug = true; - - int i; - ods("DrawStart: Screen is %d x %d", width, height); - - if (sm->fFontSize < 0.01) - sm->fFontSize = 0.01; - else if (sm->fFontSize > 1.0) - sm->fFontSize = 1.0; +static void releaseMem(Context *ctx) { + if (ctx->a_ucTexture) { + munmap(ctx->a_ucTexture, ctx->uiMappedLength); + ctx->a_ucTexture = NULL; + ctx->uiMappedLength = 0; + } + if (ctx->texture != ~0) { + glDeleteTextures(1, &ctx->texture); + ctx->texture = ~0; + } + ctx->uiLeft = ctx->uiTop = ctx->uiRight = ctx->uiBottom = 0; +} - int iHeight = (int)((height * 1.0) * sm->fFontSize); - if (iHeight > TEXT_HEIGHT) - iHeight = TEXT_HEIGHT; +static void disconnect(Context *ctx) { + releaseMem(ctx); + ctx->uiWidth = ctx->uiHeight = 0; + if (ctx->iSocket != -1) { + close(ctx->iSocket); + ctx->iSocket = -1; + } + ods("Disconnected"); +} - float s = iHeight / 60.0; - int y = 0; - int idx = 0; +static bool sendMessage(Context *ctx, struct OverlayMsg *om) { + if (ctx->iSocket != -1) { + ssize_t wantsend = sizeof(struct OverlayMsgHeader) + om->omh.iLength; + ssize_t sent = send(ctx->iSocket, om, wantsend, MSG_DONTWAIT); + if (wantsend == sent) + return true; + ods("Short write"); + } + disconnect(ctx); + return false; +} - int indexes[NUM_TEXTS]; - int yofs[NUM_TEXTS]; +static void regenTexture(Context *ctx) { + if (ctx->texture != ~0) + glDeleteTextures(1, & ctx->texture); + glGenTextures(1, &ctx->texture); + + glBindTexture(GL_TEXTURE_2D, ctx->texture); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, fBorder); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ctx->uiWidth, ctx->uiHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, ctx->a_ucTexture); +} - if (sem_trywait(sem) != 0) { - ods("Fail lock"); - return; - } +static void drawOverlay(Context *ctx, unsigned int width, unsigned int height) { + int i; - for (i = 0; i < NUM_TEXTS; i++) { - if (sm->texts[i].width == 0) { - y += iHeight / 4; - } else if (sm->texts[i].width > 0) { - indexes[idx] = i; - yofs[idx] = y; - y += iHeight; - idx++; + if (ctx->iSocket == -1) { + releaseMem(ctx); + if (! ctx->saName.sun_path[0]) + return; + ctx->iSocket = socket(AF_UNIX, SOCK_STREAM, 0); + if (ctx->iSocket == -1) { + ods("socket() failure"); + return; + } + fcntl(ctx->iSocket, F_SETFL, O_NONBLOCK, 1); + if (connect(ctx->iSocket, (struct sockaddr *)(& ctx->saName), sizeof(ctx->saName)) != 0) { + close(ctx->iSocket); + ctx->iSocket = -1; + ods("connect() failure %s", ctx->saName.sun_path); + return; } + ods("Connected"); } - int h = y; - y = (int)(height * sm->fY); + if ((ctx->uiWidth != width) || (ctx->uiHeight != height)) { + ods("Sent init"); + releaseMem(ctx); - if (sm->bTop) { - y -= h; - } else if (sm->bBottom) { - } else { - y -= h / 2; - } + ctx->uiWidth = width; + ctx->uiHeight = height; - if (y < 1) - y = 1; - if ((y + h + 1) > height) - y = height - h - 1; - - for (i = 0; i < idx; i++) { - int index = indexes[i]; - int w = (int)(sm->texts[index].width * s); - int x = (int)(width * sm->fX); - if (sm->bLeft) { - x -= w; - } else if (sm->bRight) { - } else { - x -= w / 2; - } + struct OverlayMsg om; + om.omh.uiMagic = OVERLAY_MAGIC_NUMBER; + om.omh.uiType = OVERLAY_MSGTYPE_INIT; + om.omh.iLength = sizeof(struct OverlayMsgInit); + om.omi.uiWidth = ctx->uiWidth; + om.omi.uiHeight = ctx->uiHeight; - if (x < 1) - x = 1; - if ((x + w + 1) > width) - x = width - w - 1; - - bool regen = false; + if (! sendMessage(ctx, &om)) + return; + } - if ((ctx->textures[index] == -1) || (! glIsTexture(ctx->textures[index]))) { - if (ctx->textures[index] != -1) - ods("Lost texture"); - regen = true; + while (1) { + if (ctx->omMsg.omh.iLength == -1) { + ssize_t length = recv(ctx->iSocket, ctx->omMsg.headerbuffer, sizeof(struct OverlayMsgHeader), 0); + if (length < 0) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + break; + disconnect(ctx); + return; + } else if (length != sizeof(struct OverlayMsgHeader)) { + ods("Short header read"); + disconnect(ctx); + return; + } } else { - glBindTexture(GL_TEXTURE_2D, ctx->textures[index]); - GLfloat bordercolor[4]; - glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bordercolor); - if (bordercolor[0] != fBorder[0] || bordercolor[1] != fBorder[1] || bordercolor[2] != fBorder[2] || bordercolor[3] != fBorder[3]) { - ods("Texture hijacked"); - regen = true; + ssize_t length = recv(ctx->iSocket, ctx->omMsg.msgbuffer, ctx->omMsg.omh.iLength, 0); + if (length < 0) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + break; + disconnect(ctx); + return; + } else if (length != ctx->omMsg.omh.iLength) { + ods("Short message read %x %d/%d", ctx->omMsg.omh.uiType, length, ctx->omMsg.omh.iLength); + disconnect(ctx); + return; + } + ctx->omMsg.omh.iLength = -1; + + switch (ctx->omMsg.omh.uiType) { + case OVERLAY_MSGTYPE_SHMEM: { + struct OverlayMsgShmem *oms = & ctx->omMsg.omi; + ods("SHMEM %s", oms->a_cName); + releaseMem(ctx); + int fd = shm_open(oms->a_cName, O_RDONLY, 0600); + if (fd != -1) { + struct stat buf; + fstat(fd, &buf); + if (buf.st_size >= ctx->uiWidth * ctx->uiHeight * 4) { + ctx->uiMappedLength = buf.st_size; + ctx->a_ucTexture = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (ctx->a_ucTexture != (unsigned char *) -1) { + regenTexture(ctx); + continue; + } + ctx->a_ucTexture = NULL; + } + ctx->uiMappedLength = 0; + close(fd); + } + ods("Failed to map memory"); + } + break; + case OVERLAY_MSGTYPE_BLIT: { + struct OverlayMsgBlit *omb = & ctx->omMsg.omb; + ods("BLIT %d %d %d %d", omb->x, omb->y, omb->w, omb->h); + if ((ctx->a_ucTexture != NULL) && (ctx->texture != ~0)) { + glBindTexture(GL_TEXTURE_2D, ctx->texture); + + if ((omb->x == 0) && (omb->y == 0) && (omb->w == ctx->uiWidth) && (omb->h == ctx->uiHeight)) { + ods("Optimzied fullscreen blit"); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ctx->uiWidth, ctx->uiHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, ctx->a_ucTexture); + } else { + unsigned int x = omb->x; + unsigned int y = omb->y; + unsigned int w = omb->w; + unsigned int h = omb->h; + unsigned char *ptr = (unsigned char *) malloc(w*h*4); + int r; + memset(ptr, 0, w * h * 4); + + for (r = 0; r < h; ++r) { + const unsigned char *sptr = ctx->a_ucTexture + 4 * ((y+r) * ctx->uiWidth + x); + unsigned char *dptr = ptr + 4 * w * r; + memcpy(dptr, sptr, w * 4); + } + + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_BGRA, GL_UNSIGNED_BYTE, ptr); + free(ptr); + } + } + } + break; + case OVERLAY_MSGTYPE_ACTIVE: { + struct OverlayMsgActive *oma = & ctx->omMsg.oma; + ods("ACTIVE %d %d %d %d", oma->x, oma->y, oma->w, oma->h); + ctx->uiLeft = oma->x; + ctx->uiTop = oma->y; + ctx->uiRight = oma->x + oma->w; + ctx->uiBottom = oma->y + oma->h; + } + break; + default: + break; } } - if (regen) { - ctx->uiCounter[index] = 0; - glGenTextures(1, &ctx->textures[index]); - glBindTexture(GL_TEXTURE_2D, ctx->textures[index]); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, fBorder); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } + } - if (sm->texts[index].uiCounter != ctx->uiCounter[index]) { - ods("Updating %d %d texture", sm->texts[index].width, TEXT_HEIGHT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXT_WIDTH, TEXT_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, sm->texts[index].texture); - ctx->uiCounter[index] = sm->texts[index].uiCounter; - } + if ((ctx->a_ucTexture == NULL) || (ctx->texture == ~0)) + return; - ods("Drawing text at %d %d %d %d", x, y + yofs[i], w, iHeight); + if (! glIsTexture(ctx->texture)) { + ctx->texture = ~0; + ods("Lost texture"); + regenTexture(ctx); + } else { + glBindTexture(GL_TEXTURE_2D, ctx->texture); + GLfloat bordercolor[4]; + glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bordercolor); + if (bordercolor[0] != fBorder[0] || bordercolor[1] != fBorder[1] || bordercolor[2] != fBorder[2] || bordercolor[3] != fBorder[3]) { + ods("Texture hijacked"); + regenTexture(ctx); + } + } - glPushMatrix(); + glBindTexture(GL_TEXTURE_2D, ctx->texture); + glPushMatrix(); - double xm = 0.0; - double ym = 0.0; - double xmx = (1.0 * sm->texts[index].width) / TEXT_WIDTH; - double ymx = 1.0; + float w = (float)(ctx->uiWidth); + float h = (float)(ctx->uiHeight); - unsigned int c = sm->texts[index].color; + float left = (float)(ctx->uiLeft); + float top = (float)(ctx->uiTop); + float right = (float)(ctx->uiRight); + float bottom = (float)(ctx->uiBottom); - glColor4ub((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF, (c >> 24) & 0xFF); + float xm = (left) / w; + float ym = (top) / h; + float xmx = (right) / w; + float ymx = (bottom) / h; - glTranslatef(x, y + yofs[i], 0.0); - GLint vertex[] = {0, iHeight, 0, 0, w, 0, w, iHeight }; - GLfloat tex[] = {xm, ymx, xm, ym, xmx, ym, xmx, ymx}; - glVertexPointer(2, GL_INT, 0, vertex); - glTexCoordPointer(2, GL_FLOAT, 0, tex); - glDrawArrays(GL_QUADS, 0, 4); + GLfloat vertex[] = {left, bottom, + left, top, + right, top, + right, bottom}; + GLfloat tex[] = {xm, ymx, xm, ym, xmx, ym, xmx, ymx}; + glVertexPointer(2, GL_FLOAT, 0, vertex); + glTexCoordPointer(2, GL_FLOAT, 0, tex); + glDrawArrays(GL_QUADS, 0, 4); - glPopMatrix(); - } - sem_post(sem); + glPopMatrix(); } static void drawContext(Context * ctx, int width, int height) { @@ -473,12 +542,6 @@ void glXSwapBuffers(Display * dpy, GLXDrawable draw) { if (!oglXSwapBuffers) resolveOpenGL(); - if (!sm) { - resolveSM(); - } - - if (sm) { - sm->bHooked = true; GLXContext ctx = glXGetCurrentContext(); Context *c = contexts; @@ -496,6 +559,7 @@ void glXSwapBuffers(Display * dpy, GLXDrawable draw) { ods("malloc failure"); return; } + memset(c, 0, sizeof(Context)); c->next = contexts; c->dpy = dpy; c->draw = draw; @@ -527,7 +591,6 @@ void glXSwapBuffers(Display * dpy, GLXDrawable draw) { } drawContext(c, width, height); - } } oglXSwapBuffers(dpy, draw); } @@ -565,10 +628,10 @@ static void initializeLibrary() { else bDebug = false; - ods("Mumble overlay library loaded\n"); + ods("Mumble overlay library loaded"); void *dl = dlopen("libdl.so.2", RTLD_LAZY); if (!dl) { - ods("Failed to open libdl.so.2\n"); + ods("Failed to open libdl.so.2"); } else { int i; struct link_map *lm = (struct link_map *) dl; @@ -612,7 +675,7 @@ void *dlsym(void *handle, const char *name) { void *symbol; - ods("Request for symbol %s (%p:%p)\n", name, handle, odlsym); + ods("Request for symbol %s (%p:%p)", name, handle, odlsym); if (strcmp(name, "glXSwapBuffers") == 0) { OGRAB(glXSwapBuffers); |