Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2009 Eric Anholt
  4.  * Copyright © 2009 Chris Wilson
  5.  * Copyright © 2005 Red Hat, Inc
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it either under the terms of the GNU Lesser General Public
  9.  * License version 2.1 as published by the Free Software Foundation
  10.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  11.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  12.  * notice, a recipient may use your version of this file under either
  13.  * the MPL or the LGPL.
  14.  *
  15.  * You should have received a copy of the LGPL along with this library
  16.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  18.  * You should have received a copy of the MPL along with this library
  19.  * in the file COPYING-MPL-1.1
  20.  *
  21.  * The contents of this file are subject to the Mozilla Public License
  22.  * Version 1.1 (the "License"); you may not use this file except in
  23.  * compliance with the License. You may obtain a copy of the License at
  24.  * http://www.mozilla.org/MPL/
  25.  *
  26.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  27.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  28.  * the specific language governing rights and limitations.
  29.  *
  30.  * The Original Code is the cairo graphics library.
  31.  *
  32.  * The Initial Developer of the Original Code is Red Hat, Inc.
  33.  *
  34.  * Contributor(s):
  35.  *      Carl Worth <cworth@cworth.org>
  36.  *      Chris Wilson <chris@chris-wilson.co.uk>
  37.  */
  38.  
  39. #include "cairoint.h"
  40.  
  41. #include "cairo-gl-private.h"
  42.  
  43. #include "cairo-error-private.h"
  44.  
  45. typedef struct _cairo_egl_context {
  46.     cairo_gl_context_t base;
  47.  
  48.     EGLDisplay display;
  49.     EGLContext context;
  50.  
  51.     EGLSurface dummy_surface;
  52.  
  53.     EGLContext previous_context;
  54.     EGLSurface previous_surface;
  55. } cairo_egl_context_t;
  56.  
  57. typedef struct _cairo_egl_surface {
  58.     cairo_gl_surface_t base;
  59.  
  60.     EGLSurface egl;
  61. } cairo_egl_surface_t;
  62.  
  63.  
  64. static cairo_bool_t
  65. _context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
  66.                                         EGLSurface current_surface)
  67. {
  68.     return ctx->previous_context != ctx->context ||
  69.            ctx->previous_surface != current_surface;
  70. }
  71.  
  72. static EGLSurface
  73. _egl_get_current_surface (cairo_egl_context_t *ctx)
  74. {
  75.     if (ctx->base.current_target == NULL ||
  76.         _cairo_gl_surface_is_texture (ctx->base.current_target)) {
  77.         return  ctx->dummy_surface;
  78.     }
  79.  
  80.     return ((cairo_egl_surface_t *) ctx->base.current_target)->egl;
  81. }
  82.  
  83. static void
  84. _egl_query_current_state (cairo_egl_context_t *ctx)
  85. {
  86.     ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW);
  87.     ctx->previous_context = eglGetCurrentContext ();
  88.  
  89.     /* If any of the values were none, assume they are all none. Not all
  90.        drivers seem well behaved when it comes to using these values across
  91.        multiple threads. */
  92.     if (ctx->previous_surface == EGL_NO_SURFACE ||
  93.         ctx->previous_context == EGL_NO_CONTEXT) {
  94.         ctx->previous_surface = EGL_NO_SURFACE;
  95.         ctx->previous_context = EGL_NO_CONTEXT;
  96.     }
  97. }
  98.  
  99. static void
  100. _egl_acquire (void *abstract_ctx)
  101. {
  102.     cairo_egl_context_t *ctx = abstract_ctx;
  103.     EGLSurface current_surface = _egl_get_current_surface (ctx);
  104.  
  105.     _egl_query_current_state (ctx);
  106.     if (!_context_acquisition_changed_egl_state (ctx, current_surface))
  107.         return;
  108.  
  109.     eglMakeCurrent (ctx->display,
  110.                     current_surface, current_surface, ctx->context);
  111. }
  112.  
  113. static void
  114. _egl_release (void *abstract_ctx)
  115. {
  116.     cairo_egl_context_t *ctx = abstract_ctx;
  117.     if (!ctx->base.thread_aware ||
  118.         !_context_acquisition_changed_egl_state (ctx,
  119.                                                  _egl_get_current_surface (ctx))) {
  120.         return;
  121.     }
  122.  
  123.     eglMakeCurrent (ctx->display,
  124.                     EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  125. }
  126.  
  127. static void
  128. _egl_make_current (void *abstract_ctx,
  129.                    cairo_gl_surface_t *abstract_surface)
  130. {
  131.     cairo_egl_context_t *ctx = abstract_ctx;
  132.     cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
  133.  
  134.     eglMakeCurrent(ctx->display, surface->egl, surface->egl, ctx->context);
  135. }
  136.  
  137. static void
  138. _egl_swap_buffers (void *abstract_ctx,
  139.                    cairo_gl_surface_t *abstract_surface)
  140. {
  141.     cairo_egl_context_t *ctx = abstract_ctx;
  142.     cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
  143.  
  144.     eglSwapBuffers (ctx->display, surface->egl);
  145. }
  146.  
  147. static void
  148. _egl_destroy (void *abstract_ctx)
  149. {
  150.     cairo_egl_context_t *ctx = abstract_ctx;
  151.  
  152.     eglMakeCurrent (ctx->display,
  153.                     EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  154.     if (ctx->dummy_surface != EGL_NO_SURFACE)
  155.         eglDestroySurface (ctx->display, ctx->dummy_surface);
  156. }
  157.  
  158. static cairo_bool_t
  159. _egl_make_current_surfaceless(cairo_egl_context_t *ctx)
  160. {
  161.     const char *extensions;
  162.  
  163.     extensions = eglQueryString(ctx->display, EGL_EXTENSIONS);
  164.     if (strstr(extensions, "EGL_KHR_surfaceless_context") == NULL &&
  165.         strstr(extensions, "EGL_KHR_surfaceless_opengl") == NULL)
  166.         return FALSE;
  167.  
  168.     if (!eglMakeCurrent(ctx->display,
  169.                         EGL_NO_SURFACE, EGL_NO_SURFACE, ctx->context))
  170.         return FALSE;
  171.  
  172.     return TRUE;
  173. }
  174.  
  175. cairo_device_t *
  176. cairo_egl_device_create (EGLDisplay dpy, EGLContext egl)
  177. {
  178.     cairo_egl_context_t *ctx;
  179.     cairo_status_t status;
  180.     int attribs[] = {
  181.         EGL_WIDTH, 1,
  182.         EGL_HEIGHT, 1,
  183.         EGL_NONE,
  184.     };
  185.     EGLConfig config;
  186.     EGLint numConfigs;
  187.  
  188.     ctx = calloc (1, sizeof (cairo_egl_context_t));
  189.     if (unlikely (ctx == NULL))
  190.         return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
  191.  
  192.     ctx->display = dpy;
  193.     ctx->context = egl;
  194.  
  195.     ctx->base.acquire = _egl_acquire;
  196.     ctx->base.release = _egl_release;
  197.     ctx->base.make_current = _egl_make_current;
  198.     ctx->base.swap_buffers = _egl_swap_buffers;
  199.     ctx->base.destroy = _egl_destroy;
  200.  
  201.     /* We are about the change the current state of EGL, so we should
  202.      * query the pre-existing surface now instead of later. */
  203.     _egl_query_current_state (ctx);
  204.  
  205.     if (!_egl_make_current_surfaceless (ctx)) {
  206.         /* Fall back to dummy surface, meh. */
  207.         EGLint config_attribs[] = {
  208.             EGL_CONFIG_ID, 0,
  209.             EGL_NONE
  210.         };
  211.  
  212.         /*
  213.          * In order to be able to make an egl context current when using a
  214.          * pbuffer surface, that surface must have been created with a config
  215.          * that is compatible with the context config. For Mesa, this means
  216.          * that the configs must be the same.
  217.          */
  218.         eglQueryContext (dpy, egl, EGL_CONFIG_ID, &config_attribs[1]);
  219.         eglChooseConfig (dpy, config_attribs, &config, 1, &numConfigs);
  220.  
  221.         ctx->dummy_surface = eglCreatePbufferSurface (dpy, config, attribs);
  222.         if (ctx->dummy_surface == NULL) {
  223.             free (ctx);
  224.             return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
  225.         }
  226.  
  227.         if (!eglMakeCurrent (dpy, ctx->dummy_surface, ctx->dummy_surface, egl)) {
  228.             free (ctx);
  229.             return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
  230.         }
  231.     }
  232.  
  233.     status = _cairo_gl_dispatch_init (&ctx->base.dispatch, eglGetProcAddress);
  234.     if (unlikely (status)) {
  235.         free (ctx);
  236.         return _cairo_gl_context_create_in_error (status);
  237.     }
  238.  
  239.     status = _cairo_gl_context_init (&ctx->base);
  240.     if (unlikely (status)) {
  241.         if (ctx->dummy_surface != EGL_NO_SURFACE)
  242.             eglDestroySurface (dpy, ctx->dummy_surface);
  243.         free (ctx);
  244.         return _cairo_gl_context_create_in_error (status);
  245.     }
  246.  
  247.     eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  248.  
  249.     return &ctx->base.base;
  250. }
  251.  
  252. cairo_surface_t *
  253. cairo_gl_surface_create_for_egl (cairo_device_t *device,
  254.                                  EGLSurface      egl,
  255.                                  int             width,
  256.                                  int             height)
  257. {
  258.     cairo_egl_surface_t *surface;
  259.  
  260.     if (unlikely (device->status))
  261.         return _cairo_surface_create_in_error (device->status);
  262.  
  263.     if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
  264.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
  265.  
  266.     if (width <= 0 || height <= 0)
  267.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
  268.  
  269.     surface = calloc (1, sizeof (cairo_egl_surface_t));
  270.     if (unlikely (surface == NULL))
  271.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  272.  
  273.     _cairo_gl_surface_init (device, &surface->base,
  274.                             CAIRO_CONTENT_COLOR_ALPHA, width, height);
  275.     surface->egl = egl;
  276.  
  277.     return &surface->base.base;
  278. }
  279.  
  280. static cairo_bool_t is_egl_device (cairo_device_t *device)
  281. {
  282.     return (device->backend != NULL &&
  283.             device->backend->type == CAIRO_DEVICE_TYPE_GL);
  284. }
  285.  
  286. static cairo_egl_context_t *to_egl_context (cairo_device_t *device)
  287. {
  288.     return (cairo_egl_context_t *) device;
  289. }
  290.  
  291. EGLDisplay
  292. cairo_egl_device_get_display (cairo_device_t *device)
  293. {
  294.     if (! is_egl_device (device)) {
  295.         _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
  296.         return EGL_NO_DISPLAY;
  297.     }
  298.  
  299.     return to_egl_context (device)->display;
  300. }
  301.  
  302. cairo_public EGLContext
  303. cairo_egl_device_get_context (cairo_device_t *device)
  304. {
  305.     if (! is_egl_device (device)) {
  306.         _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
  307.         return EGL_NO_CONTEXT;
  308.     }
  309.  
  310.     return to_egl_context (device)->context;
  311. }
  312.