summaryrefslogtreecommitdiff
path: root/modules/opengl/opengl.m
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2014-02-09 11:50:07 +0100
committerAlfred E. Heggestad <aeh@db.org>2014-02-09 11:50:07 +0100
commit98bf08bdcf2edd9d397f32650a8bfe62186fbecf (patch)
treeebc6ec71f44bff8c42e4eefced61948623df02fc /modules/opengl/opengl.m
parente6ad5cf4401b860ba402d4b7b3c7c254bc87a019 (diff)
baresip 0.4.10
Diffstat (limited to 'modules/opengl/opengl.m')
-rw-r--r--modules/opengl/opengl.m522
1 files changed, 522 insertions, 0 deletions
diff --git a/modules/opengl/opengl.m b/modules/opengl/opengl.m
new file mode 100644
index 0000000..d3ca972
--- /dev/null
+++ b/modules/opengl/opengl.m
@@ -0,0 +1,522 @@
+/**
+ * @file opengl.m Video driver for OpenGL on MacOSX
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <Cocoa/Cocoa.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+
+
+struct vidisp_st {
+ struct vidisp *vd; /**< Inheritance (1st) */
+ struct vidsz size; /**< Current size */
+ NSOpenGLContext *ctx;
+ NSWindow *win;
+ GLhandleARB PHandle;
+ char *prog;
+};
+
+
+static struct vidisp *vid; /**< OPENGL Video-display */
+
+
+static const char *FProgram=
+ "uniform sampler2DRect Ytex;\n"
+ "uniform sampler2DRect Utex,Vtex;\n"
+ "void main(void) {\n"
+ " float nx,ny,r,g,b,y,u,v;\n"
+ " vec4 txl,ux,vx;"
+ " nx=gl_TexCoord[0].x;\n"
+ " ny=%d.0-gl_TexCoord[0].y;\n"
+ " y=texture2DRect(Ytex,vec2(nx,ny)).r;\n"
+ " u=texture2DRect(Utex,vec2(nx/2.0,ny/2.0)).r;\n"
+ " v=texture2DRect(Vtex,vec2(nx/2.0,ny/2.0)).r;\n"
+
+ " y=1.1643*(y-0.0625);\n"
+ " u=u-0.5;\n"
+ " v=v-0.5;\n"
+
+ " r=y+1.5958*v;\n"
+ " g=y-0.39173*u-0.81290*v;\n"
+ " b=y+2.017*u;\n"
+
+ " gl_FragColor=vec4(r,g,b,1.0);\n"
+ "}\n";
+
+
+static void destructor(void *arg)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ struct vidisp_st *st = arg;
+
+ if (st->ctx) {
+ [st->ctx clearDrawable];
+ [st->ctx release];
+ }
+
+ [st->win release];
+
+ if (st->PHandle) {
+ glUseProgramObjectARB(0);
+ glDeleteObjectARB(st->PHandle);
+ }
+
+ mem_deref(st->prog);
+
+ [pool release];
+
+ mem_deref(st->vd);
+}
+
+
+static int create_window(struct vidisp_st *st)
+{
+ NSRect rect = NSMakeRect(0, 0, 100, 100);
+ NSUInteger style;
+
+ if (st->win)
+ return 0;
+
+ style = NSTitledWindowMask |
+ NSClosableWindowMask |
+ NSMiniaturizableWindowMask;
+
+ st->win = [[NSWindow alloc] initWithContentRect:rect
+ styleMask:style
+ backing:NSBackingStoreBuffered
+ defer:FALSE];
+ if (!st->win) {
+ warning("opengl: could not create NSWindow\n");
+ return ENOMEM;
+ }
+
+ [st->win setLevel:NSFloatingWindowLevel];
+ [st->win useOptimizedDrawing:YES];
+
+ return 0;
+}
+
+
+static void opengl_reset(struct vidisp_st *st, const struct vidsz *sz)
+{
+ if (st->PHandle) {
+ glUseProgramObjectARB(0);
+ glDeleteObjectARB(st->PHandle);
+ st->PHandle = 0;
+ st->prog = mem_deref(st->prog);
+ }
+
+ st->size = *sz;
+}
+
+
+static int setup_shader(struct vidisp_st *st, int width, int height)
+{
+ GLhandleARB FSHandle, PHandle;
+ const char *progv[1];
+ char buf[1024];
+ int err, i;
+
+ if (st->PHandle)
+ return 0;
+
+ err = re_sdprintf(&st->prog, FProgram, height);
+ if (err)
+ return err;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -1, 1);
+ glViewport(0, 0, width, height);
+ glClearColor(0, 0, 0, 0);
+ glColor3f(1.0f, 0.84f, 0.0f);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+
+ /* Set up program objects. */
+ PHandle = glCreateProgramObjectARB();
+ FSHandle = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+
+ /* Compile the shader. */
+ progv[0] = st->prog;
+ glShaderSourceARB(FSHandle, 1, progv, NULL);
+ glCompileShaderARB(FSHandle);
+
+ /* Print the compilation log. */
+ glGetObjectParameterivARB(FSHandle, GL_OBJECT_COMPILE_STATUS_ARB, &i);
+ if (i != 1) {
+ warning("opengl: shader compile failed\n");
+ return ENOSYS;
+ }
+
+ glGetInfoLogARB(FSHandle, sizeof(buf), NULL, buf);
+
+ /* Create a complete program object. */
+ glAttachObjectARB(PHandle, FSHandle);
+ glLinkProgramARB(PHandle);
+
+ /* And print the link log. */
+ glGetInfoLogARB(PHandle, sizeof(buf), NULL, buf);
+
+ /* Finally, use the program. */
+ glUseProgramObjectARB(PHandle);
+
+ st->PHandle = PHandle;
+
+ return 0;
+}
+
+
+static int alloc(struct vidisp_st **stp, struct vidisp *vd,
+ struct vidisp_prm *prm, const char *dev,
+ vidisp_resize_h *resizeh, void *arg)
+{
+ NSOpenGLPixelFormatAttribute attr[] = {
+ NSOpenGLPFAColorSize, 32,
+ NSOpenGLPFADepthSize, 16,
+ NSOpenGLPFADoubleBuffer,
+ 0
+ };
+ NSOpenGLPixelFormat *fmt;
+ NSAutoreleasePool *pool;
+ struct vidisp_st *st;
+ GLint vsync = 1;
+ int err = 0;
+
+ (void)dev;
+ (void)resizeh;
+ (void)arg;
+
+ pool = [[NSAutoreleasePool alloc] init];
+ if (!pool)
+ return ENOMEM;
+
+ st = mem_zalloc(sizeof(*st), destructor);
+ if (!st)
+ return ENOMEM;
+
+ st->vd = mem_ref(vd);
+
+ fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
+ if (!fmt) {
+ err = ENOMEM;
+ warning("opengl: Failed creating OpenGL format\n");
+ goto out;
+ }
+
+ st->ctx = [[NSOpenGLContext alloc] initWithFormat:fmt
+ shareContext:nil];
+
+ [fmt release];
+
+ if (!st->ctx) {
+ err = ENOMEM;
+ warning("opengl: Failed creating OpenGL context\n");
+ goto out;
+ }
+
+ /* Use provided view, or create our own */
+ if (prm && prm->view) {
+ [st->ctx setView:prm->view];
+ }
+ else {
+ err = create_window(st);
+ if (err)
+ goto out;
+
+ if (prm)
+ prm->view = [st->win contentView];
+ }
+
+ /* Enable vertical sync */
+ [st->ctx setValues:&vsync forParameter:NSOpenGLCPSwapInterval];
+
+ out:
+ if (err)
+ mem_deref(st);
+ else
+ *stp = st;
+
+ [pool release];
+
+ return err;
+}
+
+
+static inline void draw_yuv(GLhandleARB PHandle, int height,
+ const uint8_t *Ytex, int linesizeY,
+ const uint8_t *Utex, int linesizeU,
+ const uint8_t *Vtex, int linesizeV)
+{
+ int i;
+
+ /* This might not be required, but should not hurt. */
+ glEnable(GL_TEXTURE_2D);
+
+ /* Select texture unit 1 as the active unit and bind the U texture. */
+ glActiveTexture(GL_TEXTURE1);
+ i = glGetUniformLocationARB(PHandle, "Utex");
+ glUniform1iARB(i,1); /* Bind Utex to texture unit 1 */
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT,1);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_EXT,0,GL_LUMINANCE,
+ linesizeU, height/2, 0,
+ GL_LUMINANCE,GL_UNSIGNED_BYTE,Utex);
+
+ /* Select texture unit 2 as the active unit and bind the V texture. */
+ glActiveTexture(GL_TEXTURE2);
+ i = glGetUniformLocationARB(PHandle, "Vtex");
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT,2);
+ glUniform1iARB(i,2); /* Bind Vtext to texture unit 2 */
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+
+ glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_EXT,0,GL_LUMINANCE,
+ linesizeV, height/2, 0,
+ GL_LUMINANCE,GL_UNSIGNED_BYTE,Vtex);
+
+ /* Select texture unit 0 as the active unit and bind the Y texture. */
+ glActiveTexture(GL_TEXTURE0);
+ i = glGetUniformLocationARB(PHandle,"Ytex");
+ glUniform1iARB(i,0); /* Bind Ytex to texture unit 0 */
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT,3);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
+
+ glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_LUMINANCE,
+ linesizeY, height, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, Ytex);
+}
+
+
+static inline void draw_blit(int width, int height)
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* Draw image */
+
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2i(0, 0);
+ glVertex2i(0, 0);
+ glTexCoord2i(width, 0);
+ glVertex2i(width, 0);
+ glTexCoord2i(width, height);
+ glVertex2i(width, height);
+ glTexCoord2i(0, height);
+ glVertex2i(0, height);
+ }
+ glEnd();
+}
+
+
+static inline void draw_rgb(const uint8_t *pic, int w, int h)
+{
+ glEnable(GL_TEXTURE_RECTANGLE_EXT);
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 1);
+
+ glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, w * h * 2, pic);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_STORAGE_HINT_APPLE,
+ GL_STORAGE_SHARED_APPLE);
+ glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, w, h, 0,
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pic);
+
+ /* draw */
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_TEXTURE_2D);
+
+ glViewport(0, 0, w, h);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glOrtho( (GLfloat)0, (GLfloat)w, (GLfloat)0, (GLfloat)h, -1.0, 1.0);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 1);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(0.0f, h);
+ glTexCoord2f(0.0f, h);
+ glVertex2f(0.0f, 0.0f);
+ glTexCoord2f(w, h);
+ glVertex2f(w, 0.0f);
+ glTexCoord2f(w, 0.0f);
+ glVertex2f(w, h);
+ }
+ glEnd();
+}
+
+
+static int display(struct vidisp_st *st, const char *title,
+ const struct vidframe *frame)
+{
+ NSAutoreleasePool *pool;
+ bool upd = false;
+ int err = 0;
+
+ pool = [[NSAutoreleasePool alloc] init];
+ if (!pool)
+ return ENOMEM;
+
+ if (!vidsz_cmp(&st->size, &frame->size)) {
+ if (st->size.w && st->size.h) {
+ info("opengl: reset: %u x %u ---> %u x %u\n",
+ st->size.w, st->size.h,
+ frame->size.w, frame->size.h);
+ }
+
+ opengl_reset(st, &frame->size);
+
+ upd = true;
+ }
+
+ if (upd && st->win) {
+
+ const NSSize size = {frame->size.w, frame->size.h};
+ char capt[256];
+
+ [st->win setContentSize:size];
+
+ if (title) {
+ re_snprintf(capt, sizeof(capt), "%s - %u x %u",
+ title, frame->size.w, frame->size.h);
+ }
+ else {
+ re_snprintf(capt, sizeof(capt), "%u x %u",
+ frame->size.w, frame->size.h);
+ }
+
+ [st->win setTitle:[NSString stringWithUTF8String:capt]];
+
+ [st->win makeKeyAndOrderFront:nil];
+ [st->win display];
+ [st->win center];
+
+ [st->ctx clearDrawable];
+ [st->ctx setView:[st->win contentView]];
+ }
+
+ [st->ctx makeCurrentContext];
+
+ if (frame->fmt == VID_FMT_YUV420P) {
+
+ if (!st->PHandle) {
+
+ debug("opengl: using Vertex shader with YUV420P\n");
+
+ err = setup_shader(st, frame->size.w, frame->size.h);
+ if (err)
+ goto out;
+ }
+
+ draw_yuv(st->PHandle, frame->size.h,
+ frame->data[0], frame->linesize[0],
+ frame->data[1], frame->linesize[1],
+ frame->data[2], frame->linesize[2]);
+ draw_blit(frame->size.w, frame->size.h);
+ }
+ else if (frame->fmt == VID_FMT_RGB32) {
+
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glViewport(0, 0, frame->size.w, frame->size.h);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ draw_rgb(frame->data[0], frame->size.w, frame->size.h);
+ }
+ else {
+ warning("opengl: unknown pixel format %s\n",
+ vidfmt_name(frame->fmt));
+ err = EINVAL;
+ }
+
+ [st->ctx flushBuffer];
+
+ out:
+ [pool release];
+
+ return err;
+}
+
+
+static void hide(struct vidisp_st *st)
+{
+ if (!st)
+ return;
+
+ [st->win orderOut:nil];
+}
+
+
+static int module_init(void)
+{
+ NSApplication *app;
+ int err;
+
+ app = [NSApplication sharedApplication];
+ if (!app)
+ return ENOSYS;
+
+ err = vidisp_register(&vid, "opengl", alloc, NULL, display, hide);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+static int module_close(void)
+{
+ vid = mem_deref(vid);
+
+ return 0;
+}
+
+
+EXPORT_SYM const struct mod_export DECL_EXPORTS(opengl) = {
+ "opengl",
+ "vidisp",
+ module_init,
+ module_close,
+};