340 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* GDK - The GIMP Drawing Kit
 | 
						|
 *
 | 
						|
 * gdkglcontext.c: GL context abstraction
 | 
						|
 * 
 | 
						|
 * Copyright © 2014  Emmanuele Bassi
 | 
						|
 *
 | 
						|
 * This library is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU Library General Public
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This library is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * Library General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Library General Public
 | 
						|
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * SECTION:gdkglcontext
 | 
						|
 * @Title: GdkGLContext
 | 
						|
 * @Short_description: OpenGL context
 | 
						|
 *
 | 
						|
 * #GdkGLContext is an object representing the platform-specific
 | 
						|
 * OpenGL drawing context.
 | 
						|
 *
 | 
						|
 * #GdkGLContexts are created for a #GdkWindow using
 | 
						|
 * gdk_window_create_gl_context(), and the context will match
 | 
						|
 * the #GdkVisual of the window.
 | 
						|
 *
 | 
						|
 * A #GdkGLContext is not tied to any particular normal framebuffer.
 | 
						|
 * For instance, it cannot draw to the #GdkWindow back buffer. The GDK
 | 
						|
 * repaint system is in full control of the painting to that. Instead,
 | 
						|
 * you can create render buffers or textures and use gdk_cairo_draw_from_gl()
 | 
						|
 * in the draw function of your widget to draw them. Then GDK will handle
 | 
						|
 * the integration of your rendering with that of other widgets.
 | 
						|
 *
 | 
						|
 * Support for #GdkGLContext is platform-specific, context creation
 | 
						|
 * can fail, returning %NULL context.
 | 
						|
 *
 | 
						|
 * A #GdkGLContext has to be made "current" in order to start using
 | 
						|
 * it, otherwise any OpenGL call will be ignored.
 | 
						|
 *
 | 
						|
 * ## Creating a new OpenGL context ##
 | 
						|
 *
 | 
						|
 * In order to create a new #GdkGLContext instance you need a
 | 
						|
 * #GdkWindow, which you typically get during the realize call
 | 
						|
 * of a widget.
 | 
						|
 *
 | 
						|
 * ## Using a GdkGLContext ##
 | 
						|
 *
 | 
						|
 * You will need to make the #GdkGLContext the current context
 | 
						|
 * before issuing OpenGL calls; the system sends OpenGL commands to
 | 
						|
 * whichever context is current. It is possible to have multiple
 | 
						|
 * contexts, so you always need to ensure that the one which you
 | 
						|
 * want to draw with is the current one before issuing commands:
 | 
						|
 *
 | 
						|
 * |[<!-- language="C" -->
 | 
						|
 *   gdk_gl_context_make_current (context);
 | 
						|
 * ]|
 | 
						|
 *
 | 
						|
 * You can now perform your drawing using OpenGL commands.
 | 
						|
 *
 | 
						|
 * You can check which #GdkGLContext is the current one by using
 | 
						|
 * gdk_gl_context_get_current(); you can also unset any #GdkGLContext
 | 
						|
 * that is currently set by calling gdk_gl_context_clear_current().
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
 | 
						|
#include "gdkglcontextprivate.h"
 | 
						|
#include "gdkdisplayprivate.h"
 | 
						|
#include "gdkvisual.h"
 | 
						|
#include "gdkinternals.h"
 | 
						|
 | 
						|
#include "gdkintl.h"
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  GdkWindow *window;
 | 
						|
  GdkVisual *visual;
 | 
						|
} GdkGLContextPrivate;
 | 
						|
 | 
						|
enum {
 | 
						|
  PROP_0,
 | 
						|
 | 
						|
  PROP_WINDOW,
 | 
						|
  PROP_VISUAL,
 | 
						|
 | 
						|
  LAST_PROP
 | 
						|
};
 | 
						|
 | 
						|
static GParamSpec *obj_pspecs[LAST_PROP] = { NULL, };
 | 
						|
 | 
						|
G_DEFINE_QUARK (gdk-gl-error-quark, gdk_gl_error)
 | 
						|
 | 
						|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkGLContext, gdk_gl_context, G_TYPE_OBJECT)
 | 
						|
 | 
						|
static void
 | 
						|
gdk_gl_context_dispose (GObject *gobject)
 | 
						|
{
 | 
						|
  GdkGLContext *context = GDK_GL_CONTEXT (gobject);
 | 
						|
  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
 | 
						|
 | 
						|
  gdk_display_destroy_gl_context (gdk_window_get_display (priv->window), context);
 | 
						|
 | 
						|
  g_clear_object (&priv->window);
 | 
						|
  g_clear_object (&priv->visual);
 | 
						|
 | 
						|
  G_OBJECT_CLASS (gdk_gl_context_parent_class)->dispose (gobject);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_gl_context_set_property (GObject      *gobject,
 | 
						|
                             guint         prop_id,
 | 
						|
                             const GValue *value,
 | 
						|
                             GParamSpec   *pspec)
 | 
						|
{
 | 
						|
  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private ((GdkGLContext *) gobject);
 | 
						|
 | 
						|
  switch (prop_id)
 | 
						|
    {
 | 
						|
    case PROP_WINDOW:
 | 
						|
      {
 | 
						|
        GdkWindow *window = g_value_get_object (value);
 | 
						|
 | 
						|
        if (window)
 | 
						|
          g_object_ref (window);
 | 
						|
 | 
						|
        if (priv->window)
 | 
						|
          g_object_unref (priv->window);
 | 
						|
 | 
						|
        priv->window = window;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_VISUAL:
 | 
						|
      {
 | 
						|
        GdkVisual *visual = g_value_get_object (value);
 | 
						|
 | 
						|
        if (visual != NULL)
 | 
						|
          priv->visual = g_object_ref (visual);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_gl_context_get_property (GObject    *gobject,
 | 
						|
                             guint       prop_id,
 | 
						|
                             GValue     *value,
 | 
						|
                             GParamSpec *pspec)
 | 
						|
{
 | 
						|
  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private ((GdkGLContext *) gobject);
 | 
						|
 | 
						|
  switch (prop_id)
 | 
						|
    {
 | 
						|
    case PROP_WINDOW:
 | 
						|
      g_value_set_object (value, priv->window);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_VISUAL:
 | 
						|
      g_value_set_object (value, priv->visual);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_gl_context_class_init (GdkGLContextClass *klass)
 | 
						|
{
 | 
						|
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 | 
						|
 | 
						|
  /**
 | 
						|
   * GdkGLContext:window:
 | 
						|
   *
 | 
						|
   * The #GdkWindow the gl context is bound to.
 | 
						|
   *
 | 
						|
   * Since: 3.16
 | 
						|
   */
 | 
						|
  obj_pspecs[PROP_WINDOW] =
 | 
						|
    g_param_spec_object ("window",
 | 
						|
                         P_("Window"),
 | 
						|
                         P_("The GDK window bound to the GL context"),
 | 
						|
                         GDK_TYPE_WINDOW,
 | 
						|
                         G_PARAM_READWRITE |
 | 
						|
                         G_PARAM_CONSTRUCT_ONLY |
 | 
						|
                         G_PARAM_STATIC_STRINGS);
 | 
						|
 | 
						|
  /**
 | 
						|
   * GdkGLContext:visual:
 | 
						|
   *
 | 
						|
   * The #GdkVisual matching the pixel format used by the context.
 | 
						|
   *
 | 
						|
   * Since: 3.16
 | 
						|
   */
 | 
						|
  obj_pspecs[PROP_VISUAL] =
 | 
						|
    g_param_spec_object ("visual",
 | 
						|
                         P_("Visual"),
 | 
						|
                         P_("The GDK visual used by the GL context"),
 | 
						|
                         GDK_TYPE_VISUAL,
 | 
						|
                         G_PARAM_READWRITE |
 | 
						|
                         G_PARAM_CONSTRUCT_ONLY |
 | 
						|
                         G_PARAM_STATIC_STRINGS);
 | 
						|
 | 
						|
  gobject_class->set_property = gdk_gl_context_set_property;
 | 
						|
  gobject_class->get_property = gdk_gl_context_get_property;
 | 
						|
  gobject_class->dispose = gdk_gl_context_dispose;
 | 
						|
 | 
						|
  g_object_class_install_properties (gobject_class, LAST_PROP, obj_pspecs);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_gl_context_init (GdkGLContext *self)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_gl_context_get_visual:
 | 
						|
 * @context: a #GdkGLContext
 | 
						|
 *
 | 
						|
 * Retrieves the #GdkVisual associated with the @context.
 | 
						|
 *
 | 
						|
 * Returns: (transfer none): the #GdkVisual
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
GdkVisual *
 | 
						|
gdk_gl_context_get_visual (GdkGLContext *context)
 | 
						|
{
 | 
						|
  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
 | 
						|
 | 
						|
  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
 | 
						|
 | 
						|
  return priv->visual;
 | 
						|
}
 | 
						|
 | 
						|
/*< private >
 | 
						|
 * gdk_gl_context_flush_buffer:
 | 
						|
 * @context: a #GdkGLContext
 | 
						|
 * @painted: The area that has been redrawn this frame
 | 
						|
 * @damage: The area that we know is actually different from the last frame
 | 
						|
 *
 | 
						|
 * Copies the back buffer to the front buffer.
 | 
						|
 *
 | 
						|
 * This function may call `glFlush()` implicitly before returning; it
 | 
						|
 * is not recommended to call `glFlush()` explicitly before calling
 | 
						|
 * this function.
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
void
 | 
						|
gdk_gl_context_flush_buffer (GdkGLContext   *context,
 | 
						|
                             cairo_region_t *painted,
 | 
						|
                             cairo_region_t *damage)
 | 
						|
{
 | 
						|
  g_return_if_fail (GDK_IS_GL_CONTEXT (context));
 | 
						|
 | 
						|
  GDK_GL_CONTEXT_GET_CLASS (context)->flush_buffer (context, painted, damage);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_gl_context_make_current:
 | 
						|
 * @context: a #GdkGLContext
 | 
						|
 *
 | 
						|
 * Makes the @context the current one.
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
void
 | 
						|
gdk_gl_context_make_current (GdkGLContext *context)
 | 
						|
{
 | 
						|
  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
 | 
						|
 | 
						|
  g_return_if_fail (GDK_IS_GL_CONTEXT (context));
 | 
						|
 | 
						|
  gdk_display_make_gl_context_current (gdk_window_get_display (priv->window), context);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_gl_context_get_window:
 | 
						|
 * @context: a #GdkGLContext
 | 
						|
 *
 | 
						|
 * Retrieves the #GdkWindow used by the @context.
 | 
						|
 *
 | 
						|
 * Returns: (transfer none): a #GdkWindow or %NULL
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
GdkWindow *
 | 
						|
gdk_gl_context_get_window (GdkGLContext *context)
 | 
						|
{
 | 
						|
  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
 | 
						|
 | 
						|
  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
 | 
						|
 | 
						|
  return priv->window;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_gl_context_clear_current:
 | 
						|
 *
 | 
						|
 * Clears the current #GdkGLContext.
 | 
						|
 *
 | 
						|
 * Any OpenGL call after this function returns will be ignored
 | 
						|
 * until gdk_gl_context_make_current() is called.
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
void
 | 
						|
gdk_gl_context_clear_current (void)
 | 
						|
{
 | 
						|
  GdkDisplay *display = gdk_display_get_default ();
 | 
						|
 | 
						|
  gdk_display_make_gl_context_current (display, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_gl_context_get_current:
 | 
						|
 *
 | 
						|
 * Retrieves the current #GdkGLContext.
 | 
						|
 *
 | 
						|
 * Returns: (transfer none): the current #GdkGLContext, or %NULL
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
GdkGLContext *
 | 
						|
gdk_gl_context_get_current (void)
 | 
						|
{
 | 
						|
  GdkDisplay *display = gdk_display_get_default ();
 | 
						|
 | 
						|
  return gdk_display_get_current_gl_context (display);
 | 
						|
}
 |