diff mbox

[2/9] gl: Add infrastructure for calling GL functions using a dispatch table

Message ID 1311602713-6182-2-git-send-email-alexandros.frantzis@linaro.org
State Accepted
Headers show

Commit Message

alexandros.frantzis@linaro.org July 25, 2011, 2:05 p.m. UTC
From: Alexandros Frantzis <alexandros.frantzis@linaro.org>

Some GL functions can be called using different names depending on the
GL version and available extensions (ARB, EXT). The dispatch table
abstracts these differences and provides a uniform API for dealing with
these functions.
---
 src/Makefile.sources            |    2 +
 src/cairo-gl-dispatch-private.h |   99 +++++++++++++++++++++++++++
 src/cairo-gl-dispatch.c         |  144 +++++++++++++++++++++++++++++++++++++++
 src/cairo-gl-private.h          |   58 ++++++++++++++++
 4 files changed, 303 insertions(+), 0 deletions(-)
 create mode 100644 src/cairo-gl-dispatch-private.h
 create mode 100644 src/cairo-gl-dispatch.c
diff mbox

Patch

diff --git a/src/Makefile.sources b/src/Makefile.sources
index ae19e7f..168429f 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -313,12 +313,14 @@  cairo_beos_cxx_sources = cairo-beos-surface.cpp
 
 cairo_gl_headers = cairo-gl.h
 cairo_gl_private = cairo-gl-private.h \
+		   cairo-gl-dispatch-private.h \
 		   cairo-gl-gradient-private.h \
 		   glew/GL/glew.h \
 		   glew/GL/glxew.h
 
 cairo_gl_sources = cairo-gl-composite.c \
 		   cairo-gl-device.c \
+		   cairo-gl-dispatch.c \
 		   cairo-gl-glyphs.c \
 		   cairo-gl-gradient.c \
 		   cairo-gl-info.c \
diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h
new file mode 100644
index 0000000..cfe737c
--- /dev/null
+++ b/src/cairo-gl-dispatch-private.h
@@ -0,0 +1,99 @@ 
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2010 Linaro Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ *      Alexandros Frantzis <alexandros.frantzis@linaro.org>
+ */
+
+#ifndef CAIRO_GL_DISPATCH_PRIVATE_H
+#define CAIRO_GL_DISPATCH_PRIVATE_H
+
+#include <stddef.h>
+#include "cairo-gl-private.h"
+
+typedef struct _cairo_gl_dispatch_entry {
+    const char *name_core;
+    const char *name_ext;
+    size_t offset;
+} cairo_gl_dispatch_entry_t;
+
+#define DISPATCH_ENTRY_ARB(name) { "gl"#name, "gl"#name"ARB", \
+				   offsetof(cairo_gl_dispatch_t, name) }
+#define DISPATCH_ENTRY_EXT(name) { "gl"#name, "gl"#name"EXT", \
+				   offsetof(cairo_gl_dispatch_t, name) }
+#define DISPATCH_ENTRY_CUSTOM(name, name2) { "gl"#name, "gl"#name2, \
+			                     offsetof(cairo_gl_dispatch_t, name)}
+#define DISPATCH_ENTRY_LAST { NULL, NULL, 0 }
+
+cairo_gl_dispatch_entry_t dispatch_buffers_entries[] = {
+    DISPATCH_ENTRY_ARB (GenBuffers),
+    DISPATCH_ENTRY_ARB (BindBuffer),
+    DISPATCH_ENTRY_ARB (BufferData),
+    DISPATCH_ENTRY_ARB (MapBuffer),
+    DISPATCH_ENTRY_ARB (UnmapBuffer),
+    DISPATCH_ENTRY_LAST
+};
+
+cairo_gl_dispatch_entry_t dispatch_shaders_entries[] = {
+    /* Shaders */
+    DISPATCH_ENTRY_CUSTOM (CreateShader, CreateShaderObjectARB),
+    DISPATCH_ENTRY_ARB    (ShaderSource),
+    DISPATCH_ENTRY_ARB    (CompileShader),
+    DISPATCH_ENTRY_CUSTOM (GetShaderiv, GetObjectParameterivARB),
+    DISPATCH_ENTRY_CUSTOM (GetShaderInfoLog, GetInfoLogARB),
+    DISPATCH_ENTRY_CUSTOM (DeleteShader, DeleteObjectARB),
+
+    /* Programs */
+    DISPATCH_ENTRY_CUSTOM (CreateProgram, CreateProgramObjectARB),
+    DISPATCH_ENTRY_CUSTOM (AttachShader, AttachObjectARB),
+    DISPATCH_ENTRY_CUSTOM (DeleteProgram, DeleteObjectARB),
+    DISPATCH_ENTRY_ARB    (LinkProgram),
+    DISPATCH_ENTRY_CUSTOM (UseProgram, UseProgramObjectARB),
+    DISPATCH_ENTRY_CUSTOM (GetProgramiv, GetObjectParameterivARB),
+    DISPATCH_ENTRY_CUSTOM (GetProgramInfoLog, GetInfoLogARB),
+
+    /* Uniforms */
+    DISPATCH_ENTRY_ARB (GetUniformLocation),
+    DISPATCH_ENTRY_ARB (Uniform1f),
+    DISPATCH_ENTRY_ARB (Uniform2f),
+    DISPATCH_ENTRY_ARB (Uniform3f),
+    DISPATCH_ENTRY_ARB (Uniform4f),
+    DISPATCH_ENTRY_ARB (UniformMatrix3fv),
+    DISPATCH_ENTRY_ARB (Uniform1i),
+    DISPATCH_ENTRY_LAST
+};
+
+cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = {
+    DISPATCH_ENTRY_EXT (GenFramebuffers),
+    DISPATCH_ENTRY_EXT (BindFramebuffer),
+    DISPATCH_ENTRY_EXT (FramebufferTexture2D),
+    DISPATCH_ENTRY_EXT (CheckFramebufferStatus),
+    DISPATCH_ENTRY_EXT (DeleteFramebuffers),
+    DISPATCH_ENTRY_LAST
+};
+
+#endif /* CAIRO_GL_DISPATCH_PRIVATE_H */
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
new file mode 100644
index 0000000..f44d3b8
--- /dev/null
+++ b/src/cairo-gl-dispatch.c
@@ -0,0 +1,144 @@ 
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2010 Linaro Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ *      Alexandros Frantzis <alexandros.frantzis@linaro.org>
+ */
+
+#include "cairo-gl-private.h"
+#include "cairo-gl-dispatch-private.h"
+
+static void
+_cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
+				 cairo_gl_get_proc_addr_func_t get_proc_addr,
+				 cairo_gl_dispatch_entry_t *entries,
+				 cairo_bool_t use_ext)
+{
+    cairo_gl_dispatch_entry_t *entry = entries;
+
+    while (entry->name_core != NULL) {
+	void *dispatch_ptr = &((char *) dispatch)[entry->offset];
+	const char *name = use_ext ? entry->name_ext :
+				     entry->name_core;
+
+	cairo_gl_generic_func_t func = get_proc_addr (name);
+
+	*((cairo_gl_generic_func_t *) dispatch_ptr) = func;
+
+	++entry;
+    }
+
+}
+
+static cairo_status_t
+_cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
+				 cairo_gl_get_proc_addr_func_t get_proc_addr,
+				 int gl_version)
+{
+    cairo_bool_t use_ext;
+
+    if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5))
+	use_ext = 0;
+    else if (_cairo_gl_has_extension ("GL_ARB_vertex_buffer_object"))
+	use_ext = 1;
+    else
+	return CAIRO_STATUS_DEVICE_ERROR;
+
+    _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
+				     dispatch_buffers_entries, use_ext);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
+				 cairo_gl_get_proc_addr_func_t get_proc_addr,
+				 int gl_version)
+{
+    cairo_bool_t use_ext;
+
+    /* Note: shader support is not necessary at the moment */
+    if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
+	use_ext = 0;
+    else if (_cairo_gl_has_extension ("GL_ARB_shader_objects"))
+	use_ext = 1;
+    else
+	return CAIRO_STATUS_SUCCESS;
+
+    _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
+				     dispatch_shaders_entries, use_ext);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
+			     cairo_gl_get_proc_addr_func_t get_proc_addr,
+			     int gl_version)
+{
+    cairo_bool_t use_ext;
+
+    if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
+	_cairo_gl_has_extension ("GL_ARB_framebuffer_object"))
+	use_ext = 0;
+    else if (_cairo_gl_has_extension ("GL_EXT_framebuffer_object"))
+	use_ext = 1;
+    else
+	return CAIRO_STATUS_DEVICE_ERROR;
+
+    _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
+				     dispatch_fbo_entries, use_ext);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
+			 cairo_gl_get_proc_addr_func_t get_proc_addr)
+{
+    cairo_status_t status;
+    int gl_version;
+
+    gl_version = _cairo_gl_get_version ();
+
+    status = _cairo_gl_dispatch_init_buffers (dispatch, get_proc_addr,
+					      gl_version);
+    if (status != CAIRO_STATUS_SUCCESS)
+	return status;
+
+    status = _cairo_gl_dispatch_init_shaders (dispatch, get_proc_addr,
+					      gl_version);
+    if (status != CAIRO_STATUS_SUCCESS)
+	return status;
+
+    status = _cairo_gl_dispatch_init_fbo (dispatch, get_proc_addr,
+					  gl_version);
+    if (status != CAIRO_STATUS_SUCCESS)
+	return status;
+
+    return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 2a818aa..a050e18 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -175,6 +175,59 @@  typedef struct cairo_gl_operand {
     unsigned int vertex_offset;
 } cairo_gl_operand_t;
 
+typedef void (*cairo_gl_generic_func_t)(void);
+typedef cairo_gl_generic_func_t (*cairo_gl_get_proc_addr_func_t)(const char *procname);
+
+typedef struct _cairo_gl_dispatch {
+    /* Buffers */
+    void (*GenBuffers) (GLsizei n, GLuint *buffers);
+    void (*BindBuffer) (GLenum target, GLuint buffer);
+    void (*BufferData) (GLenum target, GLsizeiptr size,
+			  const GLvoid* data, GLenum usage);
+    GLvoid *(*MapBuffer) (GLenum target, GLenum access);
+    GLboolean (*UnmapBuffer) (GLenum target);
+
+    /* Shaders */
+    GLuint (*CreateShader) (GLenum type);
+    void (*ShaderSource) (GLuint shader, GLsizei count,
+			    const GLchar** string, const GLint* length);
+    void (*CompileShader) (GLuint shader);
+    void (*GetShaderiv) (GLuint shader, GLenum pname, GLint *params);
+    void (*GetShaderInfoLog) (GLuint shader, GLsizei bufSize,
+				GLsizei *length, GLchar *infoLog);
+    void (*DeleteShader) (GLuint shader);
+
+    /* Programs */
+    GLuint (*CreateProgram) (void);
+    void (*AttachShader) (GLuint program, GLuint shader);
+    void (*DeleteProgram) (GLuint program);
+    void (*LinkProgram) (GLuint program);
+    void (*UseProgram) (GLuint program);
+    void (*GetProgramiv) (GLuint program, GLenum pname, GLint *params);
+    void (*GetProgramInfoLog) (GLuint program, GLsizei bufSize,
+				 GLsizei *length, GLchar *infoLog);
+
+    /* Uniforms */
+    GLint (*GetUniformLocation) (GLuint program, const GLchar* name);
+    void (*Uniform1f) (GLint location, GLfloat x);
+    void (*Uniform2f) (GLint location, GLfloat x, GLfloat y);
+    void (*Uniform3f) (GLint location, GLfloat x, GLfloat y, GLfloat z);
+    void (*Uniform4f) (GLint location, GLfloat x, GLfloat y, GLfloat z,
+			 GLfloat w);
+    void (*UniformMatrix3fv) (GLint location, GLsizei count,
+				GLboolean transpose, const GLfloat *value);
+    void (*Uniform1i) (GLint location, GLint x);
+
+    /* Framebuffer objects */
+    void (*GenFramebuffers) (GLsizei n, GLuint* framebuffers);
+    void (*BindFramebuffer) (GLenum target, GLuint framebuffer);
+    void (*FramebufferTexture2D) (GLenum target, GLenum attachment,
+				    GLenum textarget, GLuint texture,
+				    GLint level);
+    GLenum (*CheckFramebufferStatus) (GLenum target);
+    void (*DeleteFramebuffers) (GLsizei n, const GLuint* framebuffers);
+} cairo_gl_dispatch_t;
+
 struct _cairo_gl_context {
     cairo_device_t base;
 
@@ -489,6 +542,11 @@  _cairo_gl_get_version (void);
 cairo_private cairo_bool_t
 _cairo_gl_has_extension (const char *ext);
 
+cairo_private cairo_status_t
+_cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch,
+			cairo_gl_get_proc_addr_func_t get_proc_addr);
+
+
 slim_hidden_proto (cairo_gl_surface_create);
 slim_hidden_proto (cairo_gl_surface_create_for_texture);