Initial revision of the VIGS module for OS X
authorPatrick Porlan <patrick.porlan@intel.com>
Wed, 18 Sep 2013 13:14:49 +0000 (15:14 +0200)
committerPatrick Porlan <patrick.porlan@intel.com>
Mon, 23 Sep 2013 13:41:18 +0000 (15:41 +0200)
hw/vigs_gl_backend_agl.c

index 5d3d3fc90cacbd86ffe4f83ff7696f94d4ed0b87..19a334c9ce2428369fc4f70f31ca63938ff8823d 100644 (file)
 #include "vigs_gl_backend.h"
 #include "vigs_log.h"
+#include <OpenGL/OpenGL.h>
+#include <AGL/agl.h>
+#include <glib.h>
+#include <dlfcn.h>
+
+
+#define LIBGL_IMAGE_NAME \
+"/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
+
+#define VIGS_GL_GET_PROC(func, proc_name) \
+    do { \
+        *(void**)(&gl_backend_agl->base.func) = dlsym(gl_backend_agl->handle, #proc_name); \
+        if (!gl_backend_agl->base.func) { \
+            VIGS_LOG_CRITICAL("Unable to load " #proc_name " symbol"); \
+            goto fail; \
+        } \
+    } while (0)
 
 struct vigs_gl_backend_agl
 {
     struct vigs_gl_backend base;
+    
+    void *handle;
+    AGLContext context;
+    AGLPbuffer surface;
+    AGLPixelFormat pixfmt;
 };
 
+
+static int vigs_gl_backend_agl_choose_config(struct vigs_gl_backend_agl *gl_backend_agl)
+{
+    const int attrib_list[] = {
+        AGL_RGBA,
+        AGL_ACCELERATED,
+        AGL_MINIMUM_POLICY,
+        AGL_BUFFER_SIZE, 32,
+        AGL_RED_SIZE, 8,
+        AGL_GREEN_SIZE, 8,
+        AGL_BLUE_SIZE, 8,
+        AGL_ALPHA_SIZE, 8,
+        AGL_DEPTH_SIZE, 24,
+        AGL_STENCIL_SIZE, 8,
+        AGL_NO_RECOVERY,
+        AGL_DOUBLEBUFFER,
+        AGL_PBUFFER,
+        AGL_NONE
+    };
+    AGLPixelFormat pixfmt;
+  
+    /* Select first AGL pixel format matching our constraints */
+    
+    pixfmt = aglChoosePixelFormat(NULL, 0, attrib_list);
+    
+    gl_backend_agl->pixfmt = pixfmt;
+    
+    return (pixfmt != NULL);
+}
+
+
+static bool vigs_gl_backend_agl_create_surface(struct vigs_gl_backend_agl *gl_backend_agl,
+                                               int config_id)
+{
+    gl_backend_agl->surface = NULL;
+    
+    aglCreatePBuffer(2048, 2048, GL_TEXTURE_2D, GL_RGBA, 0, &gl_backend_agl->surface);
+    
+    if (!gl_backend_agl->surface) {
+        VIGS_LOG_CRITICAL("aglCreatePBuffer failed");
+        return false;
+    }
+    
+    return true;
+}
+
+
+static bool vigs_gl_backend_agl_create_context(struct vigs_gl_backend_agl *gl_backend_agl)
+{
+    gl_backend_agl->context = aglCreateContext(gl_backend_agl->pixfmt, NULL);
+    
+    if (!gl_backend_agl->context) {
+        VIGS_LOG_CRITICAL("aglCreateContext failed");
+        return false;
+    }
+    
+    return true;
+}
+
+
+static void vigs_gl_backend_agl_destroy(struct vigs_backend *backend)
+{
+    struct vigs_gl_backend_agl *gl_backend_agl = (struct vigs_gl_backend_agl*)backend;
+    
+    vigs_gl_backend_cleanup(&gl_backend_agl->base);
+    
+    if (gl_backend_agl->surface) {
+        aglDestroyPBuffer(gl_backend_agl->surface);
+    }
+    
+    if (gl_backend_agl->context) {
+        aglDestroyContext(gl_backend_agl->context);
+    }
+    
+    if (gl_backend_agl->handle) {
+        dlclose(gl_backend_agl->handle);
+    }
+    
+    vigs_backend_cleanup(&gl_backend_agl->base.base);
+    
+    g_free(gl_backend_agl);
+    
+    VIGS_LOG_DEBUG("destroyed");
+}
+
+
+static bool vigs_gl_backend_agl_has_current(struct vigs_gl_backend *gl_backend)
+{
+    return aglGetCurrentContext() != NULL;
+}
+
+
+static bool vigs_gl_backend_agl_make_current(struct vigs_gl_backend *gl_backend,
+                                             bool enable)
+{
+    struct vigs_gl_backend_agl *gl_backend_agl =
+    (struct vigs_gl_backend_agl*)gl_backend;
+    AGLPbuffer buf = NULL;
+    AGLContext context = gl_backend_agl->context;
+    
+    if (enable) {
+        buf = gl_backend_agl->surface;
+        
+        if (!buf) {
+            VIGS_LOG_CRITICAL("surface retrieval failed");
+            return false;
+        }
+        
+        if (aglSetPBuffer(context, buf, 0, 0, 0) == GL_FALSE) {
+            VIGS_LOG_CRITICAL("aglSetPBuffer failed");
+            return false;
+        }
+            
+        if (aglSetCurrentContext(context) == GL_FALSE) {
+            VIGS_LOG_CRITICAL("aglSetCurrentContext failed");
+            aglSetPBuffer(context, NULL, 0, 0, 0);
+            return false;
+        }
+    } else {
+        if (aglSetCurrentContext(NULL) == GL_FALSE) {
+            VIGS_LOG_CRITICAL("aglSetCurrentContext(NULL) failed");
+            return false;
+        }
+    }
+    
+    return true;
+}
+
+
 struct vigs_backend *vigs_gl_backend_create(void *display)
 {
+    struct vigs_gl_backend_agl *gl_backend_agl;
+    int config_id;
+    
+    gl_backend_agl = g_malloc0(sizeof(*gl_backend_agl));
+    
+    vigs_backend_init(&gl_backend_agl->base.base,
+                      &gl_backend_agl->base.ws_info.base);
+    
+    gl_backend_agl->handle = dlopen(LIBGL_IMAGE_NAME, RTLD_GLOBAL);
+    
+    VIGS_GL_GET_PROC(GenTextures, glGenTextures);
+    VIGS_GL_GET_PROC(DeleteTextures, glDeleteTextures);
+    VIGS_GL_GET_PROC(BindTexture, glBindTexture);
+    VIGS_GL_GET_PROC(Begin, glBegin);
+    VIGS_GL_GET_PROC(End, glEnd);
+    VIGS_GL_GET_PROC(CullFace, glCullFace);
+    VIGS_GL_GET_PROC(TexParameterf, glTexParameterf);
+    VIGS_GL_GET_PROC(TexParameterfv, glTexParameterfv);
+    VIGS_GL_GET_PROC(TexParameteri, glTexParameteri);
+    VIGS_GL_GET_PROC(TexParameteriv, glTexParameteriv);
+    VIGS_GL_GET_PROC(TexImage2D, glTexImage2D);
+    VIGS_GL_GET_PROC(TexSubImage2D, glTexSubImage2D);
+    VIGS_GL_GET_PROC(TexEnvf, glTexEnvf);
+    VIGS_GL_GET_PROC(TexEnvfv, glTexEnvfv);
+    VIGS_GL_GET_PROC(TexEnvi, glTexEnvi);
+    VIGS_GL_GET_PROC(TexEnviv, glTexEnviv);
+    VIGS_GL_GET_PROC(Clear, glClear);
+    VIGS_GL_GET_PROC(ClearColor, glClearColor);
+    VIGS_GL_GET_PROC(Disable, glDisable);
+    VIGS_GL_GET_PROC(Enable, glEnable);
+    VIGS_GL_GET_PROC(Finish, glFinish);
+    VIGS_GL_GET_PROC(Flush, glFlush);
+    VIGS_GL_GET_PROC(PixelStorei, glPixelStorei);
+    VIGS_GL_GET_PROC(ReadPixels, glReadPixels);
+    VIGS_GL_GET_PROC(Viewport, glViewport);
+    VIGS_GL_GET_PROC(GenFramebuffers, glGenFramebuffersEXT);
+    VIGS_GL_GET_PROC(GenRenderbuffers, glGenRenderbuffersEXT);
+    VIGS_GL_GET_PROC(DeleteFramebuffers, glDeleteFramebuffersEXT);
+    VIGS_GL_GET_PROC(DeleteRenderbuffers, glDeleteRenderbuffersEXT);
+    VIGS_GL_GET_PROC(BindFramebuffer, glBindFramebufferEXT);
+    VIGS_GL_GET_PROC(BindRenderbuffer, glBindRenderbufferEXT);
+    VIGS_GL_GET_PROC(RenderbufferStorage, glRenderbufferStorageEXT);
+    VIGS_GL_GET_PROC(FramebufferRenderbuffer, glFramebufferRenderbufferEXT);
+    VIGS_GL_GET_PROC(FramebufferTexture2D, glFramebufferTexture2DEXT);
+    VIGS_GL_GET_PROC(GetIntegerv, glGetIntegerv);
+    VIGS_GL_GET_PROC(GetString, glGetString);
+    VIGS_GL_GET_PROC(LoadIdentity, glLoadIdentity);
+    VIGS_GL_GET_PROC(MatrixMode, glMatrixMode);
+    VIGS_GL_GET_PROC(Ortho, glOrtho);
+    VIGS_GL_GET_PROC(EnableClientState, glEnableClientState);
+    VIGS_GL_GET_PROC(DisableClientState, glDisableClientState);
+    VIGS_GL_GET_PROC(Color4f, glColor4f);
+    VIGS_GL_GET_PROC(TexCoordPointer, glTexCoordPointer);
+    VIGS_GL_GET_PROC(VertexPointer, glVertexPointer);
+    VIGS_GL_GET_PROC(DrawArrays, glDrawArrays);
+    VIGS_GL_GET_PROC(Color4ub, glColor4ub);
+    VIGS_GL_GET_PROC(WindowPos2f, glWindowPos2f);
+    VIGS_GL_GET_PROC(PixelZoom, glPixelZoom);
+    VIGS_GL_GET_PROC(DrawPixels, glDrawPixels);
+    VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
+    VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
+    VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+    
+    config_id = vigs_gl_backend_agl_choose_config(gl_backend_agl);
+    
+    if (!config_id) {
+        goto fail;
+    }
+    
+    if (!vigs_gl_backend_agl_create_surface(gl_backend_agl, config_id)) {
+        goto fail;
+    }
+    
+    if (!vigs_gl_backend_agl_create_context(gl_backend_agl)) {
+        goto fail;
+    }
+    
+    
+    gl_backend_agl->base.base.destroy = &vigs_gl_backend_agl_destroy;
+    gl_backend_agl->base.has_current = &vigs_gl_backend_agl_has_current;
+    gl_backend_agl->base.make_current = &vigs_gl_backend_agl_make_current;
+    gl_backend_agl->base.ws_info.context = &gl_backend_agl->context;
+    
+    if (!vigs_gl_backend_init(&gl_backend_agl->base)) {
+        goto fail;
+    }
+    
+    VIGS_LOG_DEBUG("created");
+    
+    return &gl_backend_agl->base.base;
+    
+fail:
+    
+    if (gl_backend_agl->handle) {
+        dlclose(gl_backend_agl->handle);
+    }
+    
+    if (gl_backend_agl->surface) {
+        aglDestroyPBuffer(gl_backend_agl->surface);
+    }
+    
+    if (gl_backend_agl->context) {
+        aglDestroyContext(gl_backend_agl->context);  
+    }
+    
+    vigs_backend_cleanup(&gl_backend_agl->base.base);
+    
+    g_free(gl_backend_agl);
+    
     return NULL;
 }