Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorvald Natvig <slicer@users.sourceforge.net>2010-01-25 18:46:23 +0300
committerThorvald Natvig <slicer@users.sourceforge.net>2010-01-25 18:46:23 +0300
commitc00b9bfe9e20869e1acc92651ee8dafaa15479e7 (patch)
tree5b75d945dd594272fbd8670b88387f1c9eb28489 /overlay_gl
parenteaf4fc0821e811d3194b2809ef548032b858356c (diff)
Socket-based linux overlay
Diffstat (limited to 'overlay_gl')
-rw-r--r--overlay_gl/overlay.c427
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);