From 0d562c42345aa1641ba6e2fa3ce6070432210eb6 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Wed, 28 Mar 2012 18:08:47 +0100 Subject: [PATCH] cairo-gl: Add a configure option to dlopen libGL Instead of directly linking to libGL all of the core GL symbols that Cairo uses have now been added to the cairo_gl_dispatch_t table and they are all accessed indirectly. A configure option has been added called --enable-dlopen-gl which will cause -lGL to be removed from the list of library dependencies from the GL pkg-config and instead the GLX and EGL contexts will dlopen libGL.so.1. The GLX context additionally uses the dlopen'd library to query all of the glX* functions. This option helps to avoid loading in a large library unless a GL surface is actually used. With the nVidia binary driver this can be quite a large memory saving. It also helps to avoid conflicts with applications that are trying to use a different GL library (such as GLESv2) but that want to use Cairo for non-GL surfaces. https://bugs.freedesktop.org/show_bug.cgi?id=47480 --- configure.ac | 35 ++++++++++- perf/Makefile.am | 4 + src/cairo-egl-context.c | 26 ++++++++ src/cairo-gl-composite.c | 82 +++++++++++++++--------- src/cairo-gl-device.c | 55 +++++++++------- src/cairo-gl-dispatch-private.h | 35 ++++++++++ src/cairo-gl-dispatch.c | 29 +++++++-- src/cairo-gl-glyphs.c | 2 +- src/cairo-gl-gradient.c | 10 ++-- src/cairo-gl-info.c | 13 ++-- src/cairo-gl-msaa-compositor.c | 51 ++++++++------- src/cairo-gl-private.h | 60 ++++++++++++++++- src/cairo-gl-shaders.c | 11 ++-- src/cairo-gl-surface.c | 60 +++++++++-------- src/cairo-glx-context.c | 136 ++++++++++++++++++++++++++++++++++----- test/Makefile.am | 4 + util/cairo-sphinx/Makefile.am | 5 ++ 17 files changed, 468 insertions(+), 150 deletions(-) diff --git a/configure.ac b/configure.ac index cedfebe..b7d8141 100644 --- a/configure.ac +++ b/configure.ac @@ -290,6 +290,20 @@ CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, [ ]) dnl =========================================================================== +AC_ARG_ENABLE(dlopen-gl, + AS_HELP_STRING([--enable-dlopen-gl], + [If set Cairo will dlopen libGL.so.1 instead of directly linking against it]), + dl_open_gl=$enableval, + dl_open_gl=no) + +AS_IF([test "x$dl_open_gl" = "xyes"], [ + AS_IF([test "x$have_dl" != "xyes" -o "x$have_dlsym" != "xyes"], + [AC_MSG_ERROR([--enable-dl-opengl requires libdl])]) + AC_DEFINE(CAIRO_DLOPEN_GL, 1, [Defined if Cairo should dlopen libGL.so.1]) +]) + +AM_CONDITIONAL(CAIRO_DLOPEN_GL, [test "x$dl_open_gl" = "xyes"]) + CAIRO_ENABLE_SURFACE_BACKEND(gl, OpenGL, no, [ gl_REQUIRES="gl" PKG_CHECK_MODULES(gl, $gl_REQUIRES,, [ @@ -297,13 +311,28 @@ CAIRO_ENABLE_SURFACE_BACKEND(gl, OpenGL, no, [ AC_CHECK_HEADER(GL/gl.h,, [use_gl="no (gl.pc nor OpenGL headers not found)"]) if test "x$use_gl" = "xyes"; then gl_NONPKGCONFIG_CFLAGS= - gl_NONPKGCONFIG_LIBS="-lGL" + AS_IF([test "x$dl_open_gl" = "xyes"], + [gl_NONPKGCONFIG_LIBS=""], + [gl_NONPKGCONFIG_LIBS="-lGL"]) fi]) if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then gl_LIBS="$gl_LIBS -ldl" fi + AS_IF([test "x$dl_open_gl" = "xyes"], [ + dnl Remove -lGL from the list of libraries so we can dlopen it instead + libs= + for x in $gl_LIBS; do + AS_CASE([$x], + [-lGL], [], + [-lGLESv2], [], + [-lGLESv1_CM], [], + [*], [libs="$libs $x"]) + done + gl_LIBS="$libs" + ]) + need_glx_functions=yes need_wgl_functions=yes need_egl_functions=yes @@ -392,7 +421,9 @@ CAIRO_ENABLE_FUNCTIONS(glx, GLX, auto, [ CFLAGS="$CFLAGS $gl_CFLAGS $gl_NONPKGCONFIG_CFLAGS" AC_CHECK_HEADER(GL/glx.h,, [use_glx="no (GLX headers not found)"]) glx_NONPKGCONFIG_CFLAGS= - glx_NONPKGCONFIG_LIBS="-lGL" + AS_IF([test "x$dl_open_gl" = "xyes"], + [glx_NONPKGCONFIG_LIBS=""], + [glx_NONPKGCONFIG_LIBS="-lGL"]) CFLAGS="$save_CFLAGS" else use_glx="no (not required by any backend)" diff --git a/perf/Makefile.am b/perf/Makefile.am index 92f0dfc..87c116a 100644 --- a/perf/Makefile.am +++ b/perf/Makefile.am @@ -38,6 +38,10 @@ LDADD = libcairoperf.la \ $(top_builddir)/boilerplate/libcairoboilerplate.la \ $(top_builddir)/src/libcairo.la +if CAIRO_DLOPEN_GL +LDADD += -lGL +endif + cairo_perf_micro_SOURCES = $(cairo_perf_micro_sources) cairo_perf_micro_LDADD = \ $(top_builddir)/perf/micro/libcairo-perf-micro.la \ diff --git a/src/cairo-egl-context.c b/src/cairo-egl-context.c index eb1ef29..e851cd8 100644 --- a/src/cairo-egl-context.c +++ b/src/cairo-egl-context.c @@ -42,6 +42,10 @@ #include "cairo-error-private.h" +#ifdef CAIRO_DLOPEN_GL +#include +#endif + typedef struct _cairo_egl_context { cairo_gl_context_t base; @@ -49,6 +53,10 @@ typedef struct _cairo_egl_context { EGLContext context; EGLSurface dummy_surface; + +#ifdef CAIRO_DLOPEN_GL + void *gl_module; +#endif } cairo_egl_context_t; typedef struct _cairo_egl_surface { @@ -114,6 +122,10 @@ _egl_destroy (void *abstract_ctx) EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (ctx->dummy_surface != EGL_NO_SURFACE) eglDestroySurface (ctx->display, ctx->dummy_surface); + +#ifdef CAIRO_DLOPEN_GL + dlclose (ctx->gl_module); +#endif } static cairo_bool_t @@ -186,8 +198,19 @@ cairo_egl_device_create (EGLDisplay dpy, EGLContext egl) } } +#ifdef CAIRO_DLOPEN_GL + ctx->gl_module = dlopen ("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (ctx->gl_module == NULL) { + free (ctx); + return _cairo_gl_context_create_in_error (CAIRO_STATUS_DEVICE_ERROR); + } +#endif + status = _cairo_gl_dispatch_init (&ctx->base.dispatch, eglGetProcAddress); if (unlikely (status)) { +#ifdef CAIRO_DLOPEN_GL + dlclose (ctx->gl_module); +#endif free (ctx); return _cairo_gl_context_create_in_error (status); } @@ -196,6 +219,9 @@ cairo_egl_device_create (EGLDisplay dpy, EGLContext egl) if (unlikely (status)) { if (ctx->dummy_surface != EGL_NO_SURFACE) eglDestroySurface (dpy, ctx->dummy_surface); +#ifdef CAIRO_DLOPEN_GL + dlclose (ctx->gl_module); +#endif free (ctx); return _cairo_gl_context_create_in_error (status); } diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index bd7c675..c35d471 100644 --- a/src/cairo-gl-composite.c +++ b/src/cairo-gl-composite.c @@ -133,14 +133,14 @@ _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx, switch (filter) { case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: - glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + ctx->dispatch.TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + ctx->dispatch.TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BEST: case CAIRO_FILTER_BILINEAR: - glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ctx->dispatch.TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ctx->dispatch.TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; default: case CAIRO_FILTER_GAUSSIAN: @@ -159,25 +159,41 @@ _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx, switch (extend) { case CAIRO_EXTEND_NONE: if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) { - glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); } else { - glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_BORDER); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_BORDER); } break; case CAIRO_EXTEND_PAD: - glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); break; case CAIRO_EXTEND_REPEAT: - glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_REPEAT); + ctx->dispatch.TexParameteri (target, GL_TEXTURE_WRAP_S, GL_REPEAT); + ctx->dispatch.TexParameteri (target, GL_TEXTURE_WRAP_T, GL_REPEAT); break; case CAIRO_EXTEND_REFLECT: - glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_S, + GL_MIRRORED_REPEAT); + ctx->dispatch.TexParameteri (target, + GL_TEXTURE_WRAP_T, + GL_MIRRORED_REPEAT); break; } } @@ -221,8 +237,8 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx, case CAIRO_GL_OPERAND_CONSTANT: break; case CAIRO_GL_OPERAND_TEXTURE: - glActiveTexture (GL_TEXTURE0 + tex_unit); - glBindTexture (ctx->tex_target, operand->texture.tex); + ctx->dispatch.ActiveTexture (GL_TEXTURE0 + tex_unit); + ctx->dispatch.BindTexture (ctx->tex_target, operand->texture.tex); _cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->texture.attributes.extend); _cairo_gl_texture_set_filter (ctx, ctx->tex_target, @@ -237,8 +253,8 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx, case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: - glActiveTexture (GL_TEXTURE0 + tex_unit); - glBindTexture (ctx->tex_target, operand->gradient.gradient->tex); + ctx->dispatch.ActiveTexture (GL_TEXTURE0 + tex_unit); + ctx->dispatch.BindTexture (ctx->tex_target, operand->gradient.gradient->tex); _cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->gradient.extend); _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR); @@ -351,11 +367,17 @@ _cairo_gl_set_operator (cairo_gl_context_t *ctx, } if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) { - glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor); + ctx->dispatch.BlendFuncSeparate (GL_ZERO, + GL_ZERO, + src_factor, + dst_factor); } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) { - glBlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE); + ctx->dispatch.BlendFuncSeparate (src_factor, + dst_factor, + GL_ONE, + GL_ONE); } else { - glBlendFunc (src_factor, dst_factor); + ctx->dispatch.BlendFunc (src_factor, dst_factor); } } @@ -476,7 +498,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup, if (unlikely (status)) return status; - glEnable (GL_BLEND); + ctx->dispatch.Enable (GL_BLEND); component_alpha = setup->mask.type == CAIRO_GL_OPERAND_TEXTURE && @@ -558,9 +580,9 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup, cairo_region_destroy (ctx->clip_region); ctx->clip_region = cairo_region_reference (setup->clip_region); if (ctx->clip_region) - glEnable (GL_SCISSOR_TEST); + ctx->dispatch.Enable (GL_SCISSOR_TEST); else - glDisable (GL_SCISSOR_TEST); + ctx->dispatch.Disable (GL_SCISSOR_TEST); *ctx_out = ctx; @@ -576,7 +598,7 @@ _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx) { cairo_array_t* indices = &ctx->tristrip_indices; const int *indices_array = _cairo_array_index_const (indices, 0); - glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_INT, indices_array); + ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_INT, indices_array); _cairo_array_truncate (indices, 0); } @@ -585,17 +607,17 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx, unsigned int count) { if (! ctx->pre_shader) { - glDrawArrays (GL_TRIANGLES, 0, count); + ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count); } else { cairo_gl_shader_t *prev_shader = ctx->current_shader; _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE); - glDrawArrays (GL_TRIANGLES, 0, count); + ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count); _cairo_gl_set_shader (ctx, prev_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE); - glDrawArrays (GL_TRIANGLES, 0, count); + ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count); } } @@ -634,7 +656,7 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx) cairo_region_get_rectangle (ctx->clip_region, i, &rect); - glScissor (rect.x, rect.y, rect.width, rect.height); + ctx->dispatch.Scissor (rect.x, rect.y, rect.width, rect.height); _cairo_gl_composite_draw (ctx, count); } } else { @@ -895,7 +917,7 @@ _cairo_gl_composite_begin_tristrip (cairo_gl_composite_t *setup, if (! _cairo_gl_context_is_flushed (ctx)) _cairo_gl_composite_flush (ctx); - glEnable (GL_BLEND); + ctx->dispatch.Enable (GL_BLEND); status = _cairo_gl_get_shader_by_type (ctx, &setup->src, diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index 47ee94e..19be2e1 100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -89,8 +89,8 @@ _gl_flush (void *device) ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0); - glDisable (GL_SCISSOR_TEST); - glDisable (GL_BLEND); + ctx->dispatch.Disable (GL_SCISSOR_TEST); + ctx->dispatch.Disable (GL_BLEND); return _cairo_gl_context_release (ctx, status); } @@ -159,8 +159,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) { cairo_status_t status; cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - int gl_version = _cairo_gl_get_version (); - cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor (); + int gl_version = _cairo_gl_get_version (dispatch); + cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor (dispatch); const char *env; int n; @@ -187,15 +187,18 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) /* Check for required extensions */ if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) { - if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) + if (_cairo_gl_has_extension (dispatch, + "GL_ARB_texture_non_power_of_two")) ctx->tex_target = GL_TEXTURE_2D; - else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) + else if (_cairo_gl_has_extension (dispatch, + "GL_ARB_texture_rectangle")) ctx->tex_target = GL_TEXTURE_RECTANGLE; else return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); } else { - if (_cairo_gl_has_extension ("GL_OES_texture_npot")) + if (_cairo_gl_has_extension (dispatch, + "GL_OES_texture_npot")) ctx->tex_target = GL_TEXTURE_2D; else return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); @@ -203,25 +206,31 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP && gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) && - ! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object")) + ! _cairo_gl_has_extension (dispatch, + "GL_ARB_pixel_buffer_object")) return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); if (gl_flavor == CAIRO_GL_FLAVOR_ES && - ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888")) + ! _cairo_gl_has_extension (dispatch, + "GL_EXT_texture_format_BGRA8888")) return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); ctx->has_map_buffer = (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP || (gl_flavor == CAIRO_GL_FLAVOR_ES && - _cairo_gl_has_extension ("GL_OES_mapbuffer"))); + _cairo_gl_has_extension (dispatch, + "GL_OES_mapbuffer"))); ctx->has_mesa_pack_invert = - _cairo_gl_has_extension ("GL_MESA_pack_invert"); + _cairo_gl_has_extension (dispatch, + "GL_MESA_pack_invert"); ctx->has_packed_depth_stencil = ((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP && - _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) || + _cairo_gl_has_extension (dispatch, + "GL_EXT_packed_depth_stencil")) || (gl_flavor == CAIRO_GL_FLAVOR_ES && - _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"))); + _cairo_gl_has_extension (dispatch, + "GL_OES_packed_depth_stencil"))); ctx->current_operator = -1; ctx->gl_flavor = gl_flavor; @@ -253,11 +262,11 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) dispatch->GenBuffers (1, &ctx->vbo); ctx->max_framebuffer_size = 0; - glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size); + ctx->dispatch.GetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size); ctx->max_texture_size = 0; - glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size); + ctx->dispatch.GetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size); ctx->max_textures = 0; - glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures); + ctx->dispatch.GetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures); for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++) _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]); @@ -274,9 +283,9 @@ _cairo_gl_context_activate (cairo_gl_context_t *ctx, _cairo_gl_composite_flush (ctx); _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1); } - glActiveTexture (ctx->max_textures - 1); + ctx->dispatch.ActiveTexture (ctx->max_textures - 1); } else { - glActiveTexture (GL_TEXTURE0 + tex_unit); + ctx->dispatch.ActiveTexture (GL_TEXTURE0 + tex_unit); } } @@ -301,8 +310,8 @@ _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx, surface->tex, 0); #if CAIRO_HAS_GL_SURFACE - glDrawBuffer (GL_COLOR_ATTACHMENT0); - glReadBuffer (GL_COLOR_ATTACHMENT0); + ctx->dispatch.DrawBuffer (GL_COLOR_ATTACHMENT0); + ctx->dispatch.ReadBuffer (GL_COLOR_ATTACHMENT0); #endif status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER); @@ -425,12 +434,12 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx, ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0); #if CAIRO_HAS_GL_SURFACE - glDrawBuffer (GL_BACK_LEFT); - glReadBuffer (GL_BACK_LEFT); + ctx->dispatch.DrawBuffer (GL_BACK_LEFT); + ctx->dispatch.ReadBuffer (GL_BACK_LEFT); #endif } - glViewport (0, 0, surface->width, surface->height); + ctx->dispatch.Viewport (0, 0, surface->width, surface->height); if (_cairo_gl_surface_is_texture (surface)) _gl_identity_ortho (ctx->modelviewprojection_matrix, diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h index fdd0cf6..2e3da49 100644 --- a/src/cairo-gl-dispatch-private.h +++ b/src/cairo-gl-dispatch-private.h @@ -47,6 +47,8 @@ typedef struct _cairo_gl_dispatch_entry { size_t offset; } cairo_gl_dispatch_entry_t; +#define DISPATCH_ENTRY_CORE(name) { { "gl"#name, "gl"#name, "gl"#name }, \ + offsetof(cairo_gl_dispatch_t, name) } #define DISPATCH_ENTRY_ARB(name) { { "gl"#name, "gl"#name"ARB", "gl"#name }, \ offsetof(cairo_gl_dispatch_t, name) } #define DISPATCH_ENTRY_EXT(name) { { "gl"#name, "gl"#name"EXT", "gl"#name }, \ @@ -57,6 +59,39 @@ typedef struct _cairo_gl_dispatch_entry { offsetof(cairo_gl_dispatch_t, name)} #define DISPATCH_ENTRY_LAST { { NULL, NULL, NULL }, 0 } +cairo_private cairo_gl_dispatch_entry_t dispatch_core_entries[] = { + DISPATCH_ENTRY_CORE (ActiveTexture), + DISPATCH_ENTRY_CORE (BindTexture), + DISPATCH_ENTRY_CORE (BlendFunc), + DISPATCH_ENTRY_CORE (BlendFuncSeparate), + DISPATCH_ENTRY_CORE (Clear), + DISPATCH_ENTRY_CORE (ClearColor), + DISPATCH_ENTRY_CORE (ClearStencil), + DISPATCH_ENTRY_CORE (ColorMask), + DISPATCH_ENTRY_CORE (DeleteTextures), + DISPATCH_ENTRY_CORE (DepthMask), + DISPATCH_ENTRY_CORE (Disable), + DISPATCH_ENTRY_CORE (DrawArrays), + DISPATCH_ENTRY_CORE (DrawBuffer), + DISPATCH_ENTRY_CORE (DrawElements), + DISPATCH_ENTRY_CORE (Enable), + DISPATCH_ENTRY_CORE (GenTextures), + DISPATCH_ENTRY_CORE (GetError), + DISPATCH_ENTRY_CORE (GetString), + DISPATCH_ENTRY_CORE (GetIntegerv), + DISPATCH_ENTRY_CORE (PixelStorei), + DISPATCH_ENTRY_CORE (ReadBuffer), + DISPATCH_ENTRY_CORE (ReadPixels), + DISPATCH_ENTRY_CORE (Scissor), + DISPATCH_ENTRY_CORE (StencilFunc), + DISPATCH_ENTRY_CORE (StencilOp), + DISPATCH_ENTRY_CORE (TexImage2D), + DISPATCH_ENTRY_CORE (TexParameteri), + DISPATCH_ENTRY_CORE (TexSubImage2D), + DISPATCH_ENTRY_CORE (Viewport), + DISPATCH_ENTRY_LAST +}; + cairo_private cairo_gl_dispatch_entry_t dispatch_buffers_entries[] = { DISPATCH_ENTRY_ARB (GenBuffers), DISPATCH_ENTRY_ARB (BindBuffer), diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c index 5bffddd..c82bad5 100644 --- a/src/cairo-gl-dispatch.c +++ b/src/cairo-gl-dispatch.c @@ -109,6 +109,17 @@ _cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch, } static cairo_status_t +_cairo_gl_dispatch_init_core (cairo_gl_dispatch_t *dispatch, + cairo_gl_get_proc_addr_func_t get_proc_addr) +{ + _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr, + dispatch_core_entries, + CAIRO_GL_DISPATCH_NAME_CORE); + + return CAIRO_STATUS_SUCCESS; +} + +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_gl_flavor_t gl_flavor) @@ -119,7 +130,8 @@ _cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch, { if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5)) dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE; - else if (_cairo_gl_has_extension ("GL_ARB_vertex_buffer_object")) + else if (_cairo_gl_has_extension (dispatch, + "GL_ARB_vertex_buffer_object")) dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT; else return CAIRO_STATUS_DEVICE_ERROR; @@ -151,7 +163,7 @@ _cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch, { if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0)) dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE; - else if (_cairo_gl_has_extension ("GL_ARB_shader_objects")) + else if (_cairo_gl_has_extension (dispatch, "GL_ARB_shader_objects")) dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT; else return CAIRO_STATUS_DEVICE_ERROR; @@ -182,9 +194,10 @@ _cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch, if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) { if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) || - _cairo_gl_has_extension ("GL_ARB_framebuffer_object")) + _cairo_gl_has_extension (dispatch, "GL_ARB_framebuffer_object")) dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE; - else if (_cairo_gl_has_extension ("GL_EXT_framebuffer_object")) + else if (_cairo_gl_has_extension (dispatch, + "GL_EXT_framebuffer_object")) dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT; else return CAIRO_STATUS_DEVICE_ERROR; @@ -213,8 +226,12 @@ _cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch, int gl_version; cairo_gl_flavor_t gl_flavor; - gl_version = _cairo_gl_get_version (); - gl_flavor = _cairo_gl_get_flavor (); + status = _cairo_gl_dispatch_init_core (dispatch, get_proc_addr); + if (status != CAIRO_STATUS_SUCCESS) + return status; + + gl_version = _cairo_gl_get_version (dispatch); + gl_flavor = _cairo_gl_get_flavor (dispatch); status = _cairo_gl_dispatch_init_buffers (dispatch, get_proc_addr, gl_version, gl_flavor); diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c index 9756ea4..52577ec 100644 --- a/src/cairo-gl-glyphs.c +++ b/src/cairo-gl-glyphs.c @@ -130,7 +130,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx, return status; /* XXX: Make sure we use the mask texture. This should work automagically somehow */ - glActiveTexture (GL_TEXTURE1); + ctx->dispatch.ActiveTexture (GL_TEXTURE1); status = _cairo_gl_surface_draw_image (cache->surface, glyph_surface, 0, 0, glyph_surface->width, glyph_surface->height, diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c index b364b92..17de8d3 100644 --- a/src/cairo-gl-gradient.c +++ b/src/cairo-gl-gradient.c @@ -234,9 +234,9 @@ _cairo_gl_gradient_create (cairo_gl_context_t *ctx, gradient->stops = gradient->stops_embedded; memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t)); - glGenTextures (1, &gradient->tex); + ctx->dispatch.GenTextures (1, &gradient->tex); _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); - glBindTexture (ctx->tex_target, gradient->tex); + ctx->dispatch.BindTexture (ctx->tex_target, gradient->tex); data = _cairo_malloc_ab (tex_width, sizeof (uint32_t)); if (unlikely (data == NULL)) { @@ -248,8 +248,8 @@ _cairo_gl_gradient_create (cairo_gl_context_t *ctx, if (unlikely (status)) goto cleanup_data; - glTexImage2D (ctx->tex_target, 0, GL_RGBA, tex_width, 1, 0, - GL_BGRA, GL_UNSIGNED_BYTE, data); + ctx->dispatch.TexImage2D (ctx->tex_target, 0, GL_RGBA, tex_width, 1, 0, + GL_BGRA, GL_UNSIGNED_BYTE, data); free (data); @@ -289,7 +289,7 @@ _cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient) return; if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) { - glDeleteTextures (1, &gradient->tex); + ctx->dispatch.DeleteTextures (1, &gradient->tex); ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); } diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c index 12a618d..8898310 100644 --- a/src/cairo-gl-info.c +++ b/src/cairo-gl-info.c @@ -33,10 +33,10 @@ #include "cairo-gl-private.h" int -_cairo_gl_get_version (void) +_cairo_gl_get_version (cairo_gl_dispatch_t *dispatch) { int major, minor; - const char *version = (const char *) glGetString (GL_VERSION); + const char *version = (const char *) dispatch->GetString (GL_VERSION); const char *dot = version == NULL ? NULL : strchr (version, '.'); const char *major_start = dot; @@ -56,9 +56,9 @@ _cairo_gl_get_version (void) } cairo_gl_flavor_t -_cairo_gl_get_flavor (void) +_cairo_gl_get_flavor (cairo_gl_dispatch_t *dispatch) { - const char *version = (const char *) glGetString (GL_VERSION); + const char *version = (const char *) dispatch->GetString (GL_VERSION); cairo_gl_flavor_t flavor; if (version == NULL) @@ -72,9 +72,10 @@ _cairo_gl_get_flavor (void) } cairo_bool_t -_cairo_gl_has_extension (const char *ext) +_cairo_gl_has_extension (cairo_gl_dispatch_t *dispatch, + const char *ext) { - const char *extensions = (const char *) glGetString (GL_EXTENSIONS); + const char *extensions = (const char *) dispatch->GetString (GL_EXTENSIONS); size_t len = strlen (ext); const char *ext_ptr = extensions; diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c index 7d8fa08..57bcbf6 100644 --- a/src/cairo-gl-msaa-compositor.c +++ b/src/cairo-gl-msaa-compositor.c @@ -167,10 +167,10 @@ _draw_clip (cairo_gl_context_t *ctx, } static void -_disable_stencil_buffer (void) +_disable_stencil_buffer (cairo_gl_context_t *ctx) { - glDisable (GL_STENCIL_TEST); - glDepthMask (GL_FALSE); + ctx->dispatch.Disable (GL_STENCIL_TEST); + ctx->dispatch.DepthMask (GL_FALSE); } static cairo_int_status_t @@ -185,40 +185,41 @@ _draw_clip_to_stencil_buffer (cairo_gl_context_t *ctx, if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - glDepthMask (GL_TRUE); - glEnable (GL_STENCIL_TEST); - glClearStencil (0); - glClear (GL_STENCIL_BUFFER_BIT); - glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); - glStencilFunc (GL_EQUAL, 1, 0xffffffff); - glColorMask (0, 0, 0, 0); + ctx->dispatch.DepthMask (GL_TRUE); + ctx->dispatch.Enable (GL_STENCIL_TEST); + ctx->dispatch.ClearStencil (0); + ctx->dispatch.Clear (GL_STENCIL_BUFFER_BIT); + ctx->dispatch.StencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); + ctx->dispatch.StencilFunc (GL_EQUAL, 1, 0xffffffff); + ctx->dispatch.ColorMask (0, 0, 0, 0); status = _draw_clip (ctx, setup, clip); if (unlikely (status)) { - glColorMask (1, 1, 1, 1); - _disable_stencil_buffer (); + ctx->dispatch.ColorMask (1, 1, 1, 1); + _disable_stencil_buffer (ctx); return status; } /* We want to only render to the stencil buffer, so draw everything now. */ _cairo_gl_composite_flush (ctx); - glColorMask (1, 1, 1, 1); - glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc (GL_EQUAL, 1, 0xffffffff); + ctx->dispatch.ColorMask (1, 1, 1, 1); + ctx->dispatch.StencilOp (GL_KEEP, GL_KEEP, GL_KEEP); + ctx->dispatch.StencilFunc (GL_EQUAL, 1, 0xffffffff); return status;; } static void -_scissor_to_rectangle (cairo_gl_surface_t *surface, +_scissor_to_rectangle (cairo_gl_context_t *ctx, + cairo_gl_surface_t *surface, const cairo_rectangle_int_t *r) { int y = r->y; if (_cairo_gl_surface_is_texture (surface) == FALSE) y = surface->height - (r->y + r->height); - glScissor (r->x, y, r->width, r->height); - glEnable (GL_SCISSOR_TEST); + ctx->dispatch.Scissor (r->x, y, r->width, r->height); + ctx->dispatch.Enable (GL_SCISSOR_TEST); } static cairo_int_status_t @@ -235,7 +236,7 @@ _scissor_and_clip (cairo_gl_context_t *ctx, *used_stencil_buffer = FALSE; if (_cairo_composite_rectangles_can_reduce_clip (composite, clip)) { - _scissor_to_rectangle (dst, bounds); + _scissor_to_rectangle (ctx, dst, bounds); return CAIRO_INT_STATUS_SUCCESS; } @@ -243,13 +244,13 @@ _scissor_and_clip (cairo_gl_context_t *ctx, we scissor and clip using the stencil buffer */ if (clip->num_boxes > 1 || clip->path != NULL) { *used_stencil_buffer = TRUE; - _scissor_to_rectangle (dst, bounds); + _scissor_to_rectangle (ctx, dst, bounds); return _draw_clip_to_stencil_buffer (ctx, setup, clip); } /* Always interpret the clip path as ANTIALIAS_NONE */ _cairo_box_round_to_rectangle (clip->boxes, &r); - _scissor_to_rectangle (dst, &r); + _scissor_to_rectangle (ctx, dst, &r); return CAIRO_INT_STATUS_SUCCESS; } @@ -358,8 +359,8 @@ finish: _cairo_gl_composite_fini (&info.setup); if (info.ctx) { - glDisable (GL_SCISSOR_TEST); - _disable_stencil_buffer (); + info.ctx->dispatch.Disable (GL_SCISSOR_TEST); + _disable_stencil_buffer (info.ctx); status = _cairo_gl_context_release (info.ctx, status); } @@ -421,8 +422,8 @@ cleanup_setup: _cairo_gl_composite_fini (&setup); if (ctx) { - glDisable (GL_SCISSOR_TEST); - _disable_stencil_buffer (); + ctx->dispatch.Disable (GL_SCISSOR_TEST); + _disable_stencil_buffer (ctx); status = _cairo_gl_context_release (ctx, status); } cleanup_traps: diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 3afdd70..86a9cbd 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -207,6 +207,59 @@ 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 { + /* Core API */ + void (*ActiveTexture) (GLenum texture); + void (*BindTexture) (GLenum target, GLuint texture); + void (*BlendFunc) (GLenum sfactor, GLenum dfactor); + void (*BlendFuncSeparate) (GLenum sfactorRGB, + GLenum dfactorRGB, + GLenum sfactorAlpha, + GLenum dfactorAlpha); + void (*Clear) (GLbitfield mask); + void (*ClearColor) (GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha); + void (*ClearStencil) (GLint s); + void (*ColorMask) (GLboolean red, + GLboolean green, + GLboolean blue, + GLboolean alpha); + void (*DeleteTextures) (GLsizei n, const GLuint *textures); + void (*DepthMask) (GLboolean flag); + void (*Disable) (GLenum cap); + void (*DrawArrays) (GLenum mode, GLint first, GLsizei count); + void (*DrawBuffer) (GLenum mode); + void (*DrawElements) (GLenum mode, GLsizei count, + GLenum type, const GLvoid *indices); + void (*Enable) (GLenum cap); + void (*GenTextures) (GLsizei n, GLuint *textures); + GLenum (*GetError) (void); + void (*GetIntegerv) (GLenum pname, GLint *params); + const GLubyte *(*GetString) (GLenum name); + void (*PixelStorei) (GLenum pname, GLint param); + void (*ReadBuffer) (GLenum mode); + void (*ReadPixels) (GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLvoid *pixels); + void (*Scissor) (GLint x, GLint y, GLsizei width, GLsizei height); + void (*StencilFunc) (GLenum func, GLint ref, GLuint mask); + void (*StencilOp) (GLenum fail, GLenum zfail, GLenum zpass); + void (*TexImage2D) (GLenum target, GLint level, + GLint internalFormat, + GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels); + void (*TexParameteri) (GLenum target, GLenum pname, GLint param); + void (*TexSubImage2D) (GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels); + void (*Viewport) (GLint x, GLint y, + GLsizei width, GLsizei height); + /* Buffers */ void (*GenBuffers) (GLsizei n, GLuint *buffers); void (*BindBuffer) (GLenum target, GLuint buffer); @@ -614,13 +667,14 @@ cairo_private void _cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader); cairo_private int -_cairo_gl_get_version (void); +_cairo_gl_get_version (cairo_gl_dispatch_t *dispatch); cairo_private cairo_gl_flavor_t -_cairo_gl_get_flavor (void); +_cairo_gl_get_flavor (cairo_gl_dispatch_t *dispatch); cairo_private cairo_bool_t -_cairo_gl_has_extension (const char *ext); +_cairo_gl_has_extension (cairo_gl_dispatch_t *dispatch, + const char *ext); cairo_private cairo_status_t _cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch, diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c index b3af6f7..51250b1 100644 --- a/src/cairo-gl-shaders.c +++ b/src/cairo-gl-shaders.c @@ -399,10 +399,11 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx) "}\n"; cairo_status_t status; - if (_cairo_gl_get_version () >= CAIRO_GL_VERSION_ENCODE (2, 0) || - (_cairo_gl_has_extension ("GL_ARB_shader_objects") && - _cairo_gl_has_extension ("GL_ARB_fragment_shader") && - _cairo_gl_has_extension ("GL_ARB_vertex_shader"))) + if (_cairo_gl_get_version (&ctx->dispatch) >= + CAIRO_GL_VERSION_ENCODE (2, 0) || + (_cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_shader_objects") && + _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_fragment_shader") && + _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_vertex_shader"))) { ctx->shader_impl = &shader_impl_core_2_0; } @@ -975,7 +976,7 @@ _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx, * asked for a different program while a shader is bound. This shouldn't * be a performance issue, since this is only called once per compile. */ - glGetIntegerv (GL_CURRENT_PROGRAM, &saved_program); + ctx->dispatch.GetIntegerv (GL_CURRENT_PROGRAM, &saved_program); dispatch->UseProgram (shader->program); location = dispatch->GetUniformLocation (shader->program, "source_sampler"); diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index 91c860a..e04da4e 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -414,9 +414,9 @@ _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx, /* Create the texture used to store the surface's data. */ _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); - glBindTexture (ctx->tex_target, surface->tex); - glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + ctx->dispatch.BindTexture (ctx->tex_target, surface->tex); + ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); return &surface->base; } @@ -431,7 +431,7 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, GLenum format; GLuint tex; - glGenTextures (1, &tex); + ctx->dispatch.GenTextures (1, &tex); surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch_for_texture (ctx, content, tex, width, height); @@ -469,8 +469,8 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, break; } - glTexImage2D (ctx->tex_target, 0, format, width, height, 0, - format, GL_UNSIGNED_BYTE, NULL); + ctx->dispatch.TexImage2D (ctx->tex_target, 0, format, width, height, 0, + format, GL_UNSIGNED_BYTE, NULL); return &surface->base; } @@ -501,9 +501,9 @@ _cairo_gl_surface_clear (cairo_gl_surface_t *surface, a = 1.0; } - glDisable (GL_SCISSOR_TEST); - glClearColor (r, g, b, a); - glClear (GL_COLOR_BUFFER_BIT); + ctx->dispatch.Disable (GL_SCISSOR_TEST); + ctx->dispatch.ClearColor (r, g, b, a); + ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT); return _cairo_gl_context_release (ctx, status); } @@ -756,7 +756,7 @@ _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst, cairo_status_t status; _cairo_gl_composite_flush (ctx); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + ctx->dispatch.ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE, dst, FALSE); @@ -777,7 +777,7 @@ _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst, _cairo_gl_composite_fini (&setup); _cairo_gl_composite_flush (ctx); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + ctx->dispatch.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); return status; } @@ -850,7 +850,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, (src->width * cpp < src->stride - 3 || width != src->width))) { - glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + ctx->dispatch.PixelStorei (GL_UNPACK_ALIGNMENT, 1); status = _cairo_gl_surface_extract_image_data (src, src_x, src_y, width, height, &data_start_gles2); @@ -861,18 +861,22 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, } else { - glPixelStorei (GL_UNPACK_ALIGNMENT, 4); + ctx->dispatch.PixelStorei (GL_UNPACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) - glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp); + ctx->dispatch.PixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp); } _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); - glBindTexture (ctx->tex_target, dst->tex); - glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexSubImage2D (ctx->tex_target, 0, - dst_x, dst_y, width, height, - format, type, data_start); + ctx->dispatch.BindTexture (ctx->tex_target, dst->tex); + ctx->dispatch.TexParameteri (ctx->tex_target, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST); + ctx->dispatch.TexParameteri (ctx->tex_target, + GL_TEXTURE_MAG_FILTER, + GL_NEAREST); + ctx->dispatch.TexSubImage2D (ctx->tex_target, 0, + dst_x, dst_y, width, height, + format, type, data_start); free (data_start_gles2); @@ -966,7 +970,7 @@ _cairo_gl_surface_finish (void *abstract_surface) if (surface->depth_stencil) ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil); if (surface->owns_tex) - glDeleteTextures (1, &surface->tex); + ctx->dispatch.DeleteTextures (1, &surface->tex); return _cairo_gl_context_release (ctx, status); } @@ -1058,16 +1062,16 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, invert = ! _cairo_gl_surface_is_texture (surface) && ctx->has_mesa_pack_invert; - glPixelStorei (GL_PACK_ALIGNMENT, 4); + ctx->dispatch.PixelStorei (GL_PACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) - glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); + ctx->dispatch.PixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); if (invert) - glPixelStorei (GL_PACK_INVERT_MESA, 1); - glReadPixels (extents->x, extents->y, - extents->width, extents->height, - format, type, image->data); + ctx->dispatch.PixelStorei (GL_PACK_INVERT_MESA, 1); + ctx->dispatch.ReadPixels (extents->x, extents->y, + extents->width, extents->height, + format, type, image->data); if (invert) - glPixelStorei (GL_PACK_INVERT_MESA, 0); + ctx->dispatch.PixelStorei (GL_PACK_INVERT_MESA, 0); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c index 512bee8..5beaf53 100644 --- a/src/cairo-glx-context.c +++ b/src/cairo-glx-context.c @@ -44,6 +44,10 @@ #include +#ifdef CAIRO_DLOPEN_GL +#include +#endif + /* XXX needs hooking into XCloseDisplay() */ typedef struct _cairo_glx_context { @@ -54,6 +58,24 @@ typedef struct _cairo_glx_context { GLXContext context; cairo_bool_t has_multithread_makecurrent; + +#ifdef CAIRO_DLOPEN_GL + + void *gl_module; + + GLXFBConfig *(* glXChooseFBConfig) (Display *dpy, int screen, + const int *attribList, int *nitems ); + void *(* glXGetProcAddress) (const GLubyte *procname); + XVisualInfo *(* glXGetVisualFromFBConfig) (Display *dpy, + GLXFBConfig config); + Bool (* glXMakeCurrent) (Display *dpy, GLXDrawable drawable, + GLXContext ctx); + int (* glXQueryContext) (Display *dpy, GLXContext ctx, int attribute, + int *value); + const char *(* glXQueryExtensionsString) (Display *dpy, int screen); + void (* glXSwapBuffers) (Display *dpy, GLXDrawable drawable); + +#endif /* CAIRO_DLOPEN_GL */ } cairo_glx_context_t; typedef struct _cairo_glx_surface { @@ -62,6 +84,35 @@ typedef struct _cairo_glx_surface { Window win; } cairo_glx_surface_t; +#ifdef CAIRO_DLOPEN_GL + +typedef struct _cairo_glx_function { + const char *name; + size_t struct_offset; +} cairo_glx_function_t; + +#define DISPATCH_ENTRY(func) \ + { #func, offsetof (cairo_glx_context_t, func) } + +static const cairo_glx_function_t +_glx_functions[] = { + DISPATCH_ENTRY (glXChooseFBConfig), + DISPATCH_ENTRY (glXGetProcAddress), + DISPATCH_ENTRY (glXGetVisualFromFBConfig), + DISPATCH_ENTRY (glXMakeCurrent), + DISPATCH_ENTRY (glXQueryContext), + DISPATCH_ENTRY (glXQueryExtensionsString), + DISPATCH_ENTRY (glXSwapBuffers) +}; + +#define CALL_GL(ctx, func) ctx->func + +#else + +#define CALL_GL(ctx, func) func + +#endif /* CAIRO_DLOPEN_GL */ + static void _glx_acquire (void *abstract_ctx) { @@ -76,7 +127,9 @@ _glx_acquire (void *abstract_ctx) current_drawable = surface->win; } - glXMakeCurrent (ctx->display, current_drawable, ctx->context); + CALL_GL (ctx, glXMakeCurrent (ctx->display, + current_drawable, + ctx->context)); } static void @@ -86,7 +139,7 @@ _glx_make_current (void *abstract_ctx, cairo_gl_surface_t *abstract_surface) cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface; /* Set the window as the target of our context. */ - glXMakeCurrent (ctx->display, surface->win, ctx->context); + CALL_GL (ctx, glXMakeCurrent (ctx->display, surface->win, ctx->context)); } static void @@ -95,7 +148,7 @@ _glx_release (void *abstract_ctx) cairo_glx_context_t *ctx = abstract_ctx; if (!ctx->has_multithread_makecurrent) { - glXMakeCurrent (ctx->display, None, None); + CALL_GL (ctx, glXMakeCurrent (ctx->display, None, None)); } } @@ -106,7 +159,7 @@ _glx_swap_buffers (void *abstract_ctx, cairo_glx_context_t *ctx = abstract_ctx; cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface; - glXSwapBuffers (ctx->display, surface->win); + CALL_GL (ctx, glXSwapBuffers (ctx->display, surface->win)); } static void @@ -117,11 +170,18 @@ _glx_destroy (void *abstract_ctx) if (ctx->dummy_window != None) XDestroyWindow (ctx->display, ctx->dummy_window); - glXMakeCurrent (ctx->display, 0, 0); + CALL_GL (ctx, glXMakeCurrent (ctx->display, 0, 0)); + +#ifdef CAIRO_DLOPEN_GL + dlclose (ctx->gl_module); +#endif } static cairo_status_t -_glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy) +_glx_dummy_ctx (cairo_glx_context_t *ctx, + Display *dpy, + GLXContext gl_ctx, + Window *dummy) { int attr[3] = { GLX_FBCONFIG_ID, 0, None }; GLXFBConfig *config; @@ -134,14 +194,17 @@ _glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy) /* Create a dummy window created for the target GLX context that we can * use to query the available GL/GLX extensions. */ - glXQueryContext (dpy, gl_ctx, GLX_FBCONFIG_ID, &attr[1]); + CALL_GL (ctx, glXQueryContext (dpy, gl_ctx, GLX_FBCONFIG_ID, &attr[1])); cnt = 0; - config = glXChooseFBConfig (dpy, DefaultScreen (dpy), attr, &cnt); + config = CALL_GL (ctx, glXChooseFBConfig (dpy, + DefaultScreen (dpy), + attr, + &cnt)); if (unlikely (cnt == 0)) return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); - vi = glXGetVisualFromFBConfig (dpy, config[0]); + vi = CALL_GL (ctx, glXGetVisualFromFBConfig (dpy, config[0])); XFree (config); if (unlikely (vi == NULL)) @@ -163,7 +226,7 @@ _glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy) XFree (vi); XFlush (dpy); - if (unlikely (! glXMakeCurrent (dpy, win, gl_ctx))) { + if (unlikely (! CALL_GL (ctx, glXMakeCurrent (dpy, win, gl_ctx)))) { XDestroyWindow (dpy, win); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -172,6 +235,33 @@ _glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy) return CAIRO_STATUS_SUCCESS; } +#ifdef CAIRO_DLOPEN_GL + +static cairo_status_t +_glx_init_dispatch (cairo_glx_context_t *ctx) +{ + int i; + + ctx->gl_module = dlopen ("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (ctx->gl_module == NULL) + return CAIRO_STATUS_DEVICE_ERROR; + + for (i = 0; i < ARRAY_LENGTH (_glx_functions); i++) { + void *func = dlsym (ctx->gl_module, _glx_functions[i].name); + if (func == NULL) { + dlclose (ctx->gl_module); + return CAIRO_STATUS_DEVICE_ERROR; + } + + *(void **) ((unsigned char *) ctx + + _glx_functions[i].struct_offset) = func; + } + + return CAIRO_STATUS_SUCCESS; +} + +#endif /* CAIRO_DLOPEN_GL */ + cairo_device_t * cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) { @@ -180,14 +270,26 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) Window dummy = None; const char *glx_extensions; - status = _glx_dummy_ctx (dpy, gl_ctx, &dummy); - if (unlikely (status)) - return _cairo_gl_context_create_in_error (status); - ctx = calloc (1, sizeof (cairo_glx_context_t)); if (unlikely (ctx == NULL)) return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY); +#ifdef CAIRO_DLOPEN_GL + + status = _glx_init_dispatch (ctx); + if (unlikely (status)) { + free (ctx); + return _cairo_gl_context_create_in_error (status); + } + +#endif /* CAIRO_DLOPEN_GL */ + + status = _glx_dummy_ctx (ctx, dpy, gl_ctx, &dummy); + if (unlikely (status)) { + free (ctx); + return _cairo_gl_context_create_in_error (status); + } + ctx->display = dpy; ctx->dummy_window = dummy; ctx->context = gl_ctx; @@ -199,7 +301,8 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) ctx->base.destroy = _glx_destroy; status = _cairo_gl_dispatch_init (&ctx->base.dispatch, - (cairo_gl_get_proc_addr_func_t) glXGetProcAddress); + (cairo_gl_get_proc_addr_func_t) + CALL_GL (ctx, glXGetProcAddress)); if (unlikely (status)) { free (ctx); return _cairo_gl_context_create_in_error (status); @@ -211,7 +314,8 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) return _cairo_gl_context_create_in_error (status); } - glx_extensions = glXQueryExtensionsString (dpy, DefaultScreen (dpy)); + glx_extensions = + CALL_GL (ctx, glXQueryExtensionsString (dpy, DefaultScreen (dpy))); if (strstr(glx_extensions, "GLX_MESA_multithread_makecurrent")) { ctx->has_multithread_makecurrent = TRUE; } diff --git a/test/Makefile.am b/test/Makefile.am index 07826ff..7fd7d77 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -99,6 +99,10 @@ cairo_test_suite_DEPENDENCIES += \ any2ppm$(EXEEXT) endif +if CAIRO_DLOPEN_GL +cairo_test_suite_LDADD += -lGL +endif + if HAVE_SHM EXTRA_PROGRAMS += cairo-test-trace cairo_test_trace_SOURCES = \ diff --git a/util/cairo-sphinx/Makefile.am b/util/cairo-sphinx/Makefile.am index b25bd23..844c495 100644 --- a/util/cairo-sphinx/Makefile.am +++ b/util/cairo-sphinx/Makefile.am @@ -30,6 +30,11 @@ cairo_sphinx_DEPENDENCIES = \ $(top_builddir)/boilerplate/libcairoboilerplate.la \ $(top_builddir)/src/libcairo.la +if CAIRO_DLOPEN_GL +cairo_sphinx_LDADD += -lGL +cairo_sphinx_la_LIBADD += -lGL +endif + # Install rules to rebuild the libraries and add explicit dependencies $(top_builddir)/boilerplate/libcairoboilerplate.la: $(top_builddir)/src/libcairo.la cd $(top_builddir)/boilerplate && $(MAKE) $(AM_MAKEFLAGS) libcairoboilerplate.la -- 1.7.3.16.g9464b