Compare commits
40 Commits
matthiasc/
...
wip/gdk-gl
Author | SHA1 | Date | |
---|---|---|---|
|
6d22f2a46a | ||
|
4d07a9ad3a | ||
|
a8b172b803 | ||
|
78f84f42c5 | ||
|
06d48d0e9a | ||
|
a7f3f94985 | ||
|
06bd4aba2b | ||
|
5cba7de332 | ||
|
be97c75a01 | ||
|
a98d8fd8df | ||
|
7622a36c7d | ||
|
fb996eec50 | ||
|
cf0b1771da | ||
|
19a0a6196b | ||
|
3398e2ea87 | ||
|
9082c07b91 | ||
|
fd24c996df | ||
|
4e84bf5263 | ||
|
0f47f8bcae | ||
|
4b5f540f11 | ||
|
b7a5369f01 | ||
|
30548946ee | ||
|
63130913ca | ||
|
3d2237865c | ||
|
54edcca4d5 | ||
|
ca380707e3 | ||
|
a71cec0119 | ||
|
d713ae6321 | ||
|
e18136f16b | ||
|
686f9b4607 | ||
|
90cc7743d0 | ||
|
eb0e790a21 | ||
|
0500963db9 | ||
|
bc9180d610 | ||
|
6b0fc7c4d8 | ||
|
6d71c440e9 | ||
|
ffcd7983aa | ||
|
a5da2eff7d | ||
|
5052aa4a9a | ||
|
a6ee04781f |
@@ -48,6 +48,7 @@ m4_define([cairo_required_version], [1.12.0])
|
||||
m4_define([gdk_pixbuf_required_version], [2.27.1])
|
||||
m4_define([introspection_required_version], [1.39.0])
|
||||
m4_define([wayland_required_version], [1.3.90])
|
||||
m4_define([epoxy_required_version], [1.0])
|
||||
GLIB_REQUIRED_VERSION=glib_required_version
|
||||
PANGO_REQUIRED_VERSION=pango_required_version
|
||||
ATK_REQUIRED_VERSION=atk_required_version
|
||||
@@ -1325,7 +1326,7 @@ CFLAGS="$saved_cflags"
|
||||
LDFLAGS="$saved_ldflags"
|
||||
|
||||
GDK_PACKAGES="$PANGO_PACKAGES gdk-pixbuf-2.0 >= gdk_pixbuf_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version"
|
||||
GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $cairo_backends"
|
||||
GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $cairo_backends epoxy >= epoxy_required_version"
|
||||
if test "x$enable_x11_backend" = xyes; then
|
||||
GDK_PRIVATE_PACKAGES="$GDK_PRIVATE_PACKAGES pangoft2"
|
||||
fi
|
||||
|
@@ -25,6 +25,7 @@ demos = \
|
||||
event_axes.c \
|
||||
expander.c \
|
||||
gestures.c \
|
||||
glarea.c \
|
||||
headerbar.c \
|
||||
hypertext.c \
|
||||
iconview.c \
|
||||
|
@@ -95,6 +95,7 @@
|
||||
<file>expander.c</file>
|
||||
<file>flowbox.c</file>
|
||||
<file>gestures.c</file>
|
||||
<file>glarea.c</file>
|
||||
<file>headerbar.c</file>
|
||||
<file>hypertext.c</file>
|
||||
<file>iconview.c</file>
|
||||
|
230
demos/gtk-demo/glarea.c
Normal file
230
demos/gtk-demo/glarea.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/* OpenGL Area
|
||||
*
|
||||
* GtkGLArea is a widget that allows custom drawing using OpenGL calls.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
static GtkWidget *demo_window = NULL;
|
||||
|
||||
/* the GtkGLArea widget */
|
||||
static GtkWidget *gl_area = NULL;
|
||||
|
||||
enum {
|
||||
X_AXIS,
|
||||
Y_AXIS,
|
||||
Z_AXIS,
|
||||
|
||||
N_AXIS
|
||||
};
|
||||
|
||||
/* Rotation angles on each axis */
|
||||
static float rotation_angles[N_AXIS] = { 0.0 };
|
||||
|
||||
/* The object we are drawing */
|
||||
static void
|
||||
draw_triangle (void)
|
||||
{
|
||||
glColor3f (1.0f, 0.85f, 0.35f);
|
||||
glBegin (GL_TRIANGLES);
|
||||
{
|
||||
glVertex3f ( 0.0, 0.6, 0.0);
|
||||
glVertex3f (-0.2, -0.3, 0.0);
|
||||
glVertex3f ( 0.2, -0.3, 0.0);
|
||||
}
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
/* The main rendering callback */
|
||||
static gboolean
|
||||
render (GtkGLArea *area,
|
||||
GdkGLContext *context)
|
||||
{
|
||||
glClearColor (0.5, 0.5, 0.5, 1.0);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity ();
|
||||
glRotatef (rotation_angles[X_AXIS], 1, 0, 0);
|
||||
glRotatef (rotation_angles[Y_AXIS], 0, 1, 0);
|
||||
glRotatef (rotation_angles[Z_AXIS], 0, 0, 1);
|
||||
|
||||
draw_triangle ();
|
||||
|
||||
glFlush ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Initialize the GL state */
|
||||
static void
|
||||
init_gl_state (GtkWidget *widget)
|
||||
{
|
||||
GdkGLContext *context = gtk_gl_area_get_context (GTK_GL_AREA (widget));
|
||||
GdkGLPixelFormat *format = gdk_gl_context_get_pixel_format (context);
|
||||
|
||||
g_print ("GL Pixel format:\n"
|
||||
" - double-buffer: %s\n"
|
||||
" - multi-sample: %s\n"
|
||||
" - stereo: %s\n"
|
||||
" - color-size: %d, alpha-size: %d\n"
|
||||
" - depth-size: %d\n"
|
||||
" - stencil-size: %d\n"
|
||||
" - aux-buffers: %d\n"
|
||||
" - accum-size: %d\n"
|
||||
" - sample-buffers: %d\n"
|
||||
" - samples: %d\n\n",
|
||||
gdk_gl_pixel_format_get_double_buffer (format) ? "yes" : "no",
|
||||
gdk_gl_pixel_format_get_multi_sample (format) ? "yes" : "no",
|
||||
gdk_gl_pixel_format_get_stereo (format) ? "yes" : "no",
|
||||
gdk_gl_pixel_format_get_color_size (format),
|
||||
gdk_gl_pixel_format_get_alpha_size (format),
|
||||
gdk_gl_pixel_format_get_depth_size (format),
|
||||
gdk_gl_pixel_format_get_stencil_size (format),
|
||||
gdk_gl_pixel_format_get_aux_buffers (format),
|
||||
gdk_gl_pixel_format_get_accum_size (format),
|
||||
gdk_gl_pixel_format_get_sample_buffers (format),
|
||||
gdk_gl_pixel_format_get_samples (format));
|
||||
}
|
||||
|
||||
static void
|
||||
on_axis_value_change (GtkAdjustment *adjustment,
|
||||
gpointer data)
|
||||
{
|
||||
int axis = GPOINTER_TO_INT (data);
|
||||
|
||||
g_assert (axis >= 0 && axis < N_AXIS);
|
||||
|
||||
/* Update the rotation angle */
|
||||
rotation_angles[axis] = gtk_adjustment_get_value (adjustment);
|
||||
|
||||
/* Update the contents of the GL drawing area */
|
||||
gtk_widget_queue_draw (gl_area);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_axis_slider (int axis)
|
||||
{
|
||||
GtkWidget *box, *label, *slider;
|
||||
GtkAdjustment *adj;
|
||||
const char *text;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE);
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case X_AXIS:
|
||||
text = "X axis";
|
||||
break;
|
||||
|
||||
case Y_AXIS:
|
||||
text = "Y axis";
|
||||
break;
|
||||
|
||||
case Z_AXIS:
|
||||
text = "Z axis";
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
label = gtk_label_new (text);
|
||||
gtk_container_add (GTK_CONTAINER (box), label);
|
||||
gtk_widget_show (label);
|
||||
|
||||
adj = gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 12.0, 0.0);
|
||||
g_signal_connect (adj, "value-changed",
|
||||
G_CALLBACK (on_axis_value_change),
|
||||
GINT_TO_POINTER (axis));
|
||||
slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adj);
|
||||
gtk_container_add (GTK_CONTAINER (box), slider);
|
||||
gtk_widget_set_hexpand (slider, TRUE);
|
||||
gtk_widget_show (slider);
|
||||
|
||||
gtk_widget_show (box);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
static void
|
||||
close_window (GtkWidget *widget)
|
||||
{
|
||||
/* Reset the state */
|
||||
demo_window = NULL;
|
||||
gl_area = NULL;
|
||||
|
||||
rotation_angles[X_AXIS] = 0.0;
|
||||
rotation_angles[Y_AXIS] = 0.0;
|
||||
rotation_angles[Z_AXIS] = 0.0;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
create_glarea_window (GtkWidget *do_widget)
|
||||
{
|
||||
GtkWidget *window, *box, *button, *controls;
|
||||
GdkGLPixelFormat *pixel_format;
|
||||
int i;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_screen (GTK_WINDOW (window), gtk_widget_get_screen (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "GtkGLArea - Golden Triangle");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 12);
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
|
||||
gtk_box_set_spacing (GTK_BOX (box), 6);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
/* Create a new pixel format; we use this to configure the
|
||||
* GL context, and to check for features.
|
||||
*
|
||||
* We only need it to be double-buffered.
|
||||
*/
|
||||
pixel_format = gdk_gl_pixel_format_new ("double-buffer", TRUE, NULL);
|
||||
|
||||
gl_area = gtk_gl_area_new (pixel_format);
|
||||
gtk_widget_set_hexpand (gl_area, TRUE);
|
||||
gtk_widget_set_vexpand (gl_area, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), gl_area);
|
||||
|
||||
/* we use ::realize to initialize our GL state, because at that
|
||||
* point we know that the GtkGLArea is associated with windowing
|
||||
* system resources like a display, window, and GL context.
|
||||
*/
|
||||
g_signal_connect (gl_area, "realize", G_CALLBACK (init_gl_state), NULL);
|
||||
|
||||
/* the main "draw" call for GtkGLArea */
|
||||
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
|
||||
g_object_unref (pixel_format);
|
||||
|
||||
controls = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
|
||||
gtk_container_add (GTK_CONTAINER (box), controls);
|
||||
gtk_widget_set_hexpand (controls, TRUE);
|
||||
|
||||
for (i = 0; i < N_AXIS; i++)
|
||||
gtk_container_add (GTK_CONTAINER (controls), create_axis_slider (i));
|
||||
|
||||
button = gtk_button_new_with_label ("Quit");
|
||||
gtk_widget_set_hexpand (button, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
do_glarea (GtkWidget *do_widget)
|
||||
{
|
||||
if (demo_window == NULL)
|
||||
demo_window = create_glarea_window (do_widget);
|
||||
|
||||
if (!gtk_widget_get_visible (demo_window))
|
||||
gtk_widget_show_all (demo_window);
|
||||
else
|
||||
gtk_widget_destroy (demo_window);
|
||||
|
||||
return demo_window;
|
||||
}
|
@@ -32,6 +32,8 @@
|
||||
<xi:include href="xml/windows.xml" />
|
||||
<xi:include href="xml/gdkframeclock.xml" />
|
||||
<xi:include href="xml/gdkframetimings.xml" />
|
||||
<xi:include href="xml/gdkglcontext.xml" />
|
||||
<xi:include href="xml/gdkglpixelformat.xml" />
|
||||
<xi:include href="xml/events.xml" />
|
||||
<xi:include href="xml/event_structs.xml" />
|
||||
<xi:include href="xml/keys.xml" />
|
||||
|
@@ -156,6 +156,8 @@ gdk_display_supports_input_shapes
|
||||
gdk_display_supports_composite
|
||||
gdk_display_get_app_launch_context
|
||||
gdk_display_notify_startup_complete
|
||||
gdk_display_validate_gl_pixel_format
|
||||
gdk_display_get_gl_context
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GDK_DISPLAY
|
||||
@@ -1004,6 +1006,7 @@ gdk_x11_display_error_trap_pop
|
||||
gdk_x11_display_error_trap_pop_ignored
|
||||
gdk_x11_display_set_cursor_theme
|
||||
gdk_x11_display_set_window_scale
|
||||
gdk_x11_display_get_glx_version
|
||||
gdk_x11_register_standard_event_type
|
||||
gdk_x11_screen_get_screen_number
|
||||
gdk_x11_screen_get_xscreen
|
||||
@@ -1123,6 +1126,11 @@ GDK_X11_KEYMAP_CLASS
|
||||
GDK_IS_X11_KEYMAP
|
||||
GDK_IS_X11_KEYMAP_CLASS
|
||||
GDK_X11_KEYMAP_GET_CLASS
|
||||
GDK_TYPE_X11_GL_CONTEXT
|
||||
GDK_X11_GL_CONTEXT
|
||||
GDK_X11_GL_CONTEXT_CLASS
|
||||
GDK_IS_X11_GL_CONTEXT
|
||||
GDK_IS_X11_GL_CONTEXT_CLASS
|
||||
GDK_TYPE_X11_SCREEN
|
||||
GDK_X11_SCREEN
|
||||
GDK_X11_SCREEN_CLASS
|
||||
@@ -1273,3 +1281,50 @@ gdk_frame_timings_get_predicted_presentation_time
|
||||
<SUBSECTION Private>
|
||||
gdk_frame_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdkglcontext</FILE>
|
||||
GdkGLContext
|
||||
gdk_gl_context_get_display
|
||||
gdk_gl_context_get_pixel_format
|
||||
gdk_gl_context_get_visual
|
||||
gdk_gl_context_set_window
|
||||
gdk_gl_context_get_window
|
||||
gdk_gl_context_make_current
|
||||
gdk_gl_context_flush_buffer
|
||||
gdk_gl_context_update
|
||||
gdk_gl_context_clear_current
|
||||
gdk_gl_context_get_current
|
||||
<SUBSECTION Standard>
|
||||
GDK_GL_CONTEXT
|
||||
GDK_IS_GL_CONTEXT
|
||||
GDK_TYPE_GL_CONTEXT
|
||||
gdk_gl_context_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdkglpixelformat</FILE>
|
||||
GdkGLPixelFormat
|
||||
GdkGLPixelFormatProfile
|
||||
gdk_gl_pixel_format_new
|
||||
<SUBSECTION>
|
||||
gdk_gl_pixel_format_get_double_buffer
|
||||
gdk_gl_pixel_format_get_multi_sample
|
||||
gdk_gl_pixel_format_get_color_size
|
||||
gdk_gl_pixel_format_get_alpha_size
|
||||
gdk_gl_pixel_format_get_depth_size
|
||||
gdk_gl_pixel_format_get_stencil_size
|
||||
gdk_gl_pixel_format_get_accum_size
|
||||
gdk_gl_pixel_format_get_aux_buffers
|
||||
gdk_gl_pixel_format_get_sample_buffers
|
||||
gdk_gl_pixel_format_get_samples
|
||||
<SUBSECTION>
|
||||
GDK_GL_PIXEL_FORMAT_ERROR
|
||||
GdkGLPixelFormatError
|
||||
<SUBSECTION Standard>
|
||||
GDK_GL_PIXEL_FORMAT
|
||||
GDK_IS_GL_PIXEL_FORMAT
|
||||
GDK_TYPE_GL_PIXEL_FORMAT
|
||||
gdk_gl_pixel_format_error_quark
|
||||
gdk_gl_pixel_format_get_type
|
||||
</SECTION>
|
||||
|
@@ -8,6 +8,8 @@ gdk_display_get_type
|
||||
gdk_display_manager_get_type
|
||||
gdk_drag_context_get_type
|
||||
gdk_frame_clock_get_type
|
||||
gdk_gl_context_get_type
|
||||
gdk_gl_pixel_format_get_type
|
||||
gdk_keymap_get_type
|
||||
gdk_screen_get_type
|
||||
gdk_visual_get_type
|
||||
|
@@ -243,6 +243,7 @@
|
||||
<xi:include href="xml/gtkadjustment.xml" />
|
||||
<xi:include href="xml/gtkcalendar.xml" />
|
||||
<xi:include href="xml/gtkdrawingarea.xml" />
|
||||
<xi:include href="xml/gtkglarea.xml" />
|
||||
<xi:include href="xml/gtkeventbox.xml" />
|
||||
<xi:include href="xml/gtkhandlebox.xml" />
|
||||
<xi:include href="xml/gtkimcontextsimple.xml" />
|
||||
|
@@ -8153,3 +8153,22 @@ GTK_GESTURE_ZOOM_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_gesture_zoom_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkglarea</FILE>
|
||||
GtkGLArea
|
||||
GtkGLAreaClass
|
||||
gtk_gl_area_new
|
||||
gtk_gl_area_get_context
|
||||
<SUBSECTION>
|
||||
gtk_gl_area_make_current
|
||||
gtk_gl_area_flush_buffer
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_GL_AREA
|
||||
GTK_GL_AREA
|
||||
GTK_GL_AREA_CLASS
|
||||
GTK_IS_GL_AREA
|
||||
GTK_IS_GL_AREA_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_gl_area_get_type
|
||||
</SECTION>
|
||||
|
@@ -75,6 +75,8 @@ gdk_public_h_sources = \
|
||||
gdkdnd.h \
|
||||
gdkevents.h \
|
||||
gdkframetimings.h \
|
||||
gdkglcontext.h \
|
||||
gdkglpixelformat.h \
|
||||
gdkkeys.h \
|
||||
gdkkeysyms.h \
|
||||
gdkkeysyms-compat.h \
|
||||
@@ -111,6 +113,8 @@ gdk_private_headers = \
|
||||
gdkdndprivate.h \
|
||||
gdkframeclockidle.h \
|
||||
gdkframeclockprivate.h \
|
||||
gdkglcontextprivate.h \
|
||||
gdkglpixelformatprivate.h \
|
||||
gdkscreenprivate.h \
|
||||
gdkinternals.h \
|
||||
gdkintl.h \
|
||||
@@ -135,6 +139,8 @@ gdk_c_sources = \
|
||||
gdkdnd.c \
|
||||
gdkevents.c \
|
||||
gdkframetimings.c \
|
||||
gdkglcontext.c \
|
||||
gdkglpixelformat.c \
|
||||
gdkglobals.c \
|
||||
gdkkeys.c \
|
||||
gdkkeyuni.c \
|
||||
|
@@ -148,7 +148,8 @@ static const GDebugKey gdk_debug_keys[] = {
|
||||
{"draw", GDK_DEBUG_DRAW},
|
||||
{"eventloop", GDK_DEBUG_EVENTLOOP},
|
||||
{"frames", GDK_DEBUG_FRAMES},
|
||||
{"settings", GDK_DEBUG_SETTINGS}
|
||||
{"settings", GDK_DEBUG_SETTINGS},
|
||||
{"opengl", GDK_DEBUG_OPENGL},
|
||||
};
|
||||
|
||||
static gboolean
|
||||
|
@@ -41,6 +41,8 @@
|
||||
#include <gdk/gdkevents.h>
|
||||
#include <gdk/gdkframeclock.h>
|
||||
#include <gdk/gdkframetimings.h>
|
||||
#include <gdk/gdkglpixelformat.h>
|
||||
#include <gdk/gdkglcontext.h>
|
||||
#include <gdk/gdkkeys.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gdk/gdkmain.h>
|
||||
|
160
gdk/gdkdisplay.c
160
gdk/gdkdisplay.c
@@ -2225,3 +2225,163 @@ gdk_error_trap_pop (void)
|
||||
{
|
||||
return gdk_error_trap_pop_internal (TRUE);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_display_destroy_gl_context:
|
||||
* @display: a #GdkDisplay
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Destroys the platform-specific parts of the @context.
|
||||
*
|
||||
* The @context instance is still valid, though inert, after
|
||||
* this functionr returns.
|
||||
*/
|
||||
void
|
||||
gdk_display_destroy_gl_context (GdkDisplay *display,
|
||||
GdkGLContext *context)
|
||||
{
|
||||
GDK_DISPLAY_GET_CLASS (display)->destroy_gl_context (display, context);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_display_make_gl_context_current:
|
||||
* @display: a #GdkDisplay
|
||||
* @context: (optional): a #GdkGLContext, or %NULL
|
||||
* @window: (optional): a #GdkWindow, or %NULL
|
||||
*
|
||||
* Makes the given @context the current GL context, or unsets
|
||||
* the current GL context if @context is %NULL.
|
||||
*
|
||||
* Returns: %TRUE if successful
|
||||
*/
|
||||
gboolean
|
||||
gdk_display_make_gl_context_current (GdkDisplay *display,
|
||||
GdkGLContext *context,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkGLContext *current = gdk_display_get_current_gl_context (display);
|
||||
|
||||
if (current == context)
|
||||
return TRUE;
|
||||
|
||||
if (context == NULL)
|
||||
g_object_set_data (G_OBJECT (display), "-gdk-gl-current-context", NULL);
|
||||
else
|
||||
g_object_set_data_full (G_OBJECT (display), "-gdk-gl-current-context",
|
||||
g_object_ref (context),
|
||||
(GDestroyNotify) g_object_unref);
|
||||
|
||||
return GDK_DISPLAY_GET_CLASS (display)->make_gl_context_current (display, context, window);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_display_get_current_gl_context:
|
||||
* @display: a #GdkDisplay
|
||||
*
|
||||
* Retrieves the current #GdkGLContext associated with @display.
|
||||
*
|
||||
* Returns: (transfer none): the current #GdkGLContext or %NULL
|
||||
*/
|
||||
GdkGLContext *
|
||||
gdk_display_get_current_gl_context (GdkDisplay *display)
|
||||
{
|
||||
return g_object_get_data (G_OBJECT (display), "-gdk-gl-current-context");
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_display_validate_gl_pixel_format:
|
||||
* @display: a #GdkDisplay
|
||||
* @format: a #GdkGLPixelFormat
|
||||
* @validated_format: (out callee-allocates) (transfer full) (optional): return location for
|
||||
* the validated #GdkGLPixelFormat
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Validates a #GdkGLPixelFormat for the given display.
|
||||
*
|
||||
* If the pixel format is valid, and @validated_format is not %NULL, the
|
||||
* validated pixel format will be stored into @validated_format.
|
||||
*
|
||||
* If the pixel format is invalid, @error will be set.
|
||||
*
|
||||
* Returns: %TRUE if the pixel format is valid
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
gboolean
|
||||
gdk_display_validate_gl_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLPixelFormat **validated_format,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (format), FALSE);
|
||||
g_return_val_if_fail (validated_format == NULL || *validated_format == NULL, FALSE);
|
||||
|
||||
return GDK_DISPLAY_GET_CLASS (display)->validate_gl_pixel_format (display,
|
||||
format, validated_format,
|
||||
error);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_display_create_gl_context:
|
||||
* @display: a #GdkDisplay
|
||||
* @format: a #GdkGLPixelFormat
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Creates a new #GdkGLContext for the given display, with the given
|
||||
* pixel format.
|
||||
*
|
||||
* If the @format is invalid, or in case the creation of the #GdkGLContext
|
||||
* failed, @error will be set.
|
||||
*
|
||||
* Returns: (transfer full): the newly created #GdkGLContext, or
|
||||
* %NULL on error
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkGLContext *
|
||||
gdk_display_create_gl_context (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
||||
g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (format), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format, NULL, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_display_create_shared_gl_context:
|
||||
* @display: a #GdkDisplay
|
||||
* @format: a #GdkGLPixelFormat
|
||||
* @shared_context: shared #GdkGLContext
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Creates a new #GdkGLContext for the given display, with the given
|
||||
* pixel format; the newly created #GdkGLContext will share resources
|
||||
* like the texture namespace and display lists with @shared_context.
|
||||
*
|
||||
* If the @format is invalid, or in case the creation of the #GdkGLContext
|
||||
* failed, @error will be set.
|
||||
*
|
||||
* Returns: (transfer full): the newly created #GdkGLContext, or
|
||||
* %NULL on error
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkGLContext *
|
||||
gdk_display_create_shared_gl_context (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLContext *shared_context,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
||||
g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (format), NULL);
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (shared_context), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format,
|
||||
shared_context,
|
||||
error);
|
||||
}
|
||||
|
@@ -171,6 +171,21 @@ GdkDeviceManager * gdk_display_get_device_manager (GdkDisplay *display);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkAppLaunchContext *gdk_display_get_app_launch_context (GdkDisplay *display);
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gboolean gdk_display_validate_gl_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLPixelFormat **validated_format,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkGLContext * gdk_display_create_gl_context (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkGLContext * gdk_display_create_shared_gl_context (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLContext *shared_context,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_DISPLAY_H__ */
|
||||
|
@@ -225,6 +225,20 @@ struct _GdkDisplayClass
|
||||
gchar * (*utf8_to_string_target) (GdkDisplay *display,
|
||||
const gchar *text);
|
||||
|
||||
GdkGLContext * (*create_gl_context) (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLContext *share,
|
||||
GError **error);
|
||||
gboolean (*make_gl_context_current) (GdkDisplay *display,
|
||||
GdkGLContext *context,
|
||||
GdkWindow *drawable);
|
||||
void (*destroy_gl_context) (GdkDisplay *display,
|
||||
GdkGLContext *context);
|
||||
gboolean (*validate_gl_pixel_format) (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLPixelFormat **valid_format,
|
||||
GError **error);
|
||||
|
||||
/* Signals */
|
||||
void (*opened) (GdkDisplay *display);
|
||||
void (*closed) (GdkDisplay *display,
|
||||
@@ -303,6 +317,17 @@ void _gdk_display_create_window_impl (GdkDisplay *display
|
||||
gint attributes_mask);
|
||||
GdkWindow * _gdk_display_create_window (GdkDisplay *display);
|
||||
|
||||
gboolean gdk_display_validate_gl_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLPixelFormat **validated_format,
|
||||
GError **error);
|
||||
void gdk_display_destroy_gl_context (GdkDisplay *display,
|
||||
GdkGLContext *context);
|
||||
gboolean gdk_display_make_gl_context_current (GdkDisplay *display,
|
||||
GdkGLContext *context,
|
||||
GdkWindow *window);
|
||||
GdkGLContext * gdk_display_get_current_gl_context (GdkDisplay *display);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_DISPLAY_PRIVATE_H__ */
|
||||
|
648
gdk/gdkglcontext.c
Normal file
648
gdk/gdkglcontext.c
Normal file
@@ -0,0 +1,648 @@
|
||||
/* 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 via a #GdkDisplay by specifying a
|
||||
* #GdkGLPixelFormat to be used by the OpenGL context.
|
||||
*
|
||||
* Support for #GdkGLContext is platform specific; in order to
|
||||
* discover if the platform supports OpenGL, you should use the
|
||||
* #GdkGLPixelFormat class.
|
||||
*
|
||||
* A #GdkGLContext has to be associated with a #GdkWindow and
|
||||
* made "current", otherwise any OpenGL call will be ignored.
|
||||
*
|
||||
* ## Creating a new OpenGL context ##
|
||||
*
|
||||
* In order to create a new #GdkGLContext instance you need a
|
||||
* #GdkGLPixelFormat instance and a #GdkDisplay.
|
||||
*
|
||||
* The #GdkGLPixelFormat class contains configuration option that
|
||||
* you require from the windowing system to be available on the
|
||||
* #GdkGLContext.
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* GdkGLPixelFormat *format;
|
||||
*
|
||||
* format = gdk_gl_pixel_format_new ("double-buffer", TRUE,
|
||||
* "depth-size", 32,
|
||||
* NULL);
|
||||
* ]|
|
||||
*
|
||||
* The example above will create a pixel format with double buffering
|
||||
* and a depth buffer size of 32 bits.
|
||||
*
|
||||
* You can either choose to validate the pixel format, in case you
|
||||
* have the ability to change your drawing code depending on it, or
|
||||
* just ask the #GdkDisplay to create the #GdkGLContext with it, which
|
||||
* will implicitly validate the pixel format and return an error if it
|
||||
* could not find an OpenGL context that satisfied the requirements
|
||||
* of the pixel format:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* GError *error = NULL;
|
||||
*
|
||||
* // the "display" variable has been set elsewhere
|
||||
* GdkGLContext *context =
|
||||
* gdk_display_create_gl_context (display, format, &error);
|
||||
*
|
||||
* if (error != NULL)
|
||||
* {
|
||||
* // handle error condition
|
||||
* }
|
||||
*
|
||||
* // you can release the reference on the pixel format at
|
||||
* // this point
|
||||
* g_object_unref (format);
|
||||
* ]|
|
||||
*
|
||||
* ## Using a GdkGLContext ##
|
||||
*
|
||||
* In order to use a #GdkGLContext to draw with OpenGL commands
|
||||
* on a #GdkWindow, it's necessary to bind the context to the
|
||||
* window:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* // associates the window to the context
|
||||
* gdk_gl_context_set_window (context, window);
|
||||
* ]|
|
||||
*
|
||||
* This ensures that the #GdkGLContext can refer to the #GdkWindow,
|
||||
* as well as the #GdkWindow can present the result of the OpenGL
|
||||
* commands.
|
||||
*
|
||||
* You will also 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.
|
||||
*
|
||||
* Once you finished drawing your frame, and you want to present the
|
||||
* result on the window bound to the #GdkGLContext, you should call
|
||||
* gdk_gl_context_flush_buffer().
|
||||
*
|
||||
* If the #GdkWindow bound to the #GdkGLContext changes size, you
|
||||
* will need to call gdk_gl_context_update() to ensure that the OpenGL
|
||||
* viewport is kept in sync with the size of the window.
|
||||
*
|
||||
* You can detach the currently bound #GdkWindow from a #GdkGLContext
|
||||
* by using gdk_gl_context_set_window() with a %NULL argument.
|
||||
*
|
||||
* 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 "gdkglpixelformat.h"
|
||||
#include "gdkvisual.h"
|
||||
#include "gdkinternals.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
typedef struct {
|
||||
GdkDisplay *display;
|
||||
GdkGLPixelFormat *pixel_format;
|
||||
GdkWindow *window;
|
||||
GdkVisual *visual;
|
||||
|
||||
gboolean swap_interval;
|
||||
} GdkGLContextPrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_DISPLAY,
|
||||
PROP_PIXEL_FORMAT,
|
||||
PROP_WINDOW,
|
||||
PROP_VISUAL,
|
||||
|
||||
PROP_SWAP_INTERVAL,
|
||||
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *obj_pspecs[LAST_PROP] = { NULL, };
|
||||
|
||||
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 (priv->display, context);
|
||||
|
||||
g_clear_object (&priv->display);
|
||||
g_clear_object (&priv->pixel_format);
|
||||
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_DISPLAY:
|
||||
priv->display = g_object_ref (g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_PIXEL_FORMAT:
|
||||
priv->pixel_format = g_object_ref (g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_WINDOW:
|
||||
{
|
||||
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
|
||||
GdkWindow *window = g_value_get_object (value);
|
||||
|
||||
gdk_gl_context_set_window (context, window);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_VISUAL:
|
||||
{
|
||||
GdkVisual *visual = g_value_get_object (value);
|
||||
|
||||
if (visual != NULL)
|
||||
priv->visual = g_object_ref (visual);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_SWAP_INTERVAL:
|
||||
priv->swap_interval = g_value_get_boolean (value);
|
||||
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_DISPLAY:
|
||||
g_value_set_object (value, priv->display);
|
||||
break;
|
||||
|
||||
case PROP_PIXEL_FORMAT:
|
||||
g_value_set_object (value, priv->pixel_format);
|
||||
break;
|
||||
|
||||
case PROP_WINDOW:
|
||||
g_value_set_object (value, priv->window);
|
||||
break;
|
||||
|
||||
case PROP_VISUAL:
|
||||
g_value_set_object (value, priv->visual);
|
||||
break;
|
||||
|
||||
case PROP_SWAP_INTERVAL:
|
||||
g_value_set_boolean (value, priv->swap_interval);
|
||||
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:display:
|
||||
*
|
||||
* The #GdkDisplay used by the context.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_pspecs[PROP_DISPLAY] =
|
||||
g_param_spec_object ("display",
|
||||
"Display",
|
||||
"The GDK display used by the GL context",
|
||||
GDK_TYPE_DISPLAY,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLContext:pixel-format:
|
||||
*
|
||||
* The #GdkGLPixelFormat used to create the context.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_pspecs[PROP_PIXEL_FORMAT] =
|
||||
g_param_spec_object ("pixel-format",
|
||||
"Pixel Format",
|
||||
"The GDK pixel format used by the GL context",
|
||||
GDK_TYPE_GL_PIXEL_FORMAT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLContext:window:
|
||||
*
|
||||
* The #GdkWindow currently bound to the context.
|
||||
*
|
||||
* You typically need to bind a #GdkWindow to a #GdkGLContext prior
|
||||
* to calling gdk_gl_context_make_current().
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_pspecs[PROP_WINDOW] =
|
||||
g_param_spec_object ("window",
|
||||
P_("Window"),
|
||||
P_("The GDK window currently bound to the GL context"),
|
||||
GDK_TYPE_WINDOW,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLContext:visual:
|
||||
*
|
||||
* The #GdkVisual matching the #GdkGLPixelFormat used by the context.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* GdkGLContext:swap-interval:
|
||||
*
|
||||
* The swap interval of the context.
|
||||
*
|
||||
* If set to %TRUE (the default), buffers will be flushed only during
|
||||
* the vertical refresh of the display.
|
||||
*
|
||||
* If set to %FALSE, gdk_gl_context_flush_buffer() will execute
|
||||
* the buffer flush as soon as possible.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_pspecs[PROP_SWAP_INTERVAL] =
|
||||
g_param_spec_boolean ("swap-interval",
|
||||
P_("Swap Interval"),
|
||||
P_("The swap interval of the GL context"),
|
||||
TRUE,
|
||||
G_PARAM_READWRITE |
|
||||
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)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
||||
|
||||
priv->swap_interval = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_get_display:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Retrieves the #GdkDisplay associated with the @context.
|
||||
*
|
||||
* Returns: (transfer none): the #GdkDisplay
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkDisplay *
|
||||
gdk_gl_context_get_display (GdkGLContext *context)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
||||
|
||||
return priv->display;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_get_pixel_format:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Retrieves the #GdkGLPixelFormat associated with the @context.
|
||||
*
|
||||
* Returns: (transfer none): the #GdkDisplay
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkGLPixelFormat *
|
||||
gdk_gl_context_get_pixel_format (GdkGLContext *context)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
||||
|
||||
return priv->pixel_format;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_get_visual:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Retrieves the #GdkVisual associated with the @context.
|
||||
*
|
||||
* Returns: (transfer none): the #GdkVisual
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_flush_buffer:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Copies the back buffer to the front buffer.
|
||||
*
|
||||
* If the #GdkGLContext is not double buffered, this function does not
|
||||
* do anything.
|
||||
*
|
||||
* Depending on the value of the #GdkGLContext:swap-interval property,
|
||||
* the copy may take place during the vertical refresh of the display
|
||||
* rather than immediately.
|
||||
*
|
||||
* This function may call `glFlush()` implicitly before returning; it
|
||||
* is not recommended to call `glFlush()` explicitly before calling
|
||||
* this function.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
void
|
||||
gdk_gl_context_flush_buffer (GdkGLContext *context)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
GDK_GL_CONTEXT_GET_CLASS (context)->flush_buffer (context);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_make_current:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Makes the @context the current one.
|
||||
*
|
||||
* Returns: %TRUE if the context is current
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
gboolean
|
||||
gdk_gl_context_make_current (GdkGLContext *context)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
||||
|
||||
return gdk_display_make_gl_context_current (priv->display, context, priv->window);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_set_window:
|
||||
* @context: a #GdkGLContext
|
||||
* @window: (optional): a #GdkWindow, or %NULL
|
||||
*
|
||||
* Sets the #GdkWindow used to display the draw commands.
|
||||
*
|
||||
* If @window is %NULL, the @context is detached from the window.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
void
|
||||
gdk_gl_context_set_window (GdkGLContext *context,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
g_return_if_fail (window == NULL || (GDK_IS_WINDOW (window) && !GDK_WINDOW_DESTROYED (window)));
|
||||
|
||||
if (priv->window == window)
|
||||
return;
|
||||
|
||||
if (priv->window != NULL)
|
||||
gdk_window_set_gl_context (priv->window, NULL);
|
||||
|
||||
g_clear_object (&priv->window);
|
||||
|
||||
if (window != NULL)
|
||||
{
|
||||
priv->window = g_object_ref (window);
|
||||
gdk_window_set_gl_context (window, context);
|
||||
}
|
||||
|
||||
GDK_GL_CONTEXT_GET_CLASS (context)->set_window (context, window);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_get_window:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Retrieves the #GdkWindow used by the @context.
|
||||
*
|
||||
* Returns: (transfer none): a #GdkWindow or %NULL
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
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_update:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Updates the @context when the #GdkWindow used to display the
|
||||
* rendering changes size or position.
|
||||
*
|
||||
* Typically, you will call this function after calling
|
||||
* gdk_window_resize() or gdk_window_move_resize().
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
void
|
||||
gdk_gl_context_update (GdkGLContext *context)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
if (priv->window == NULL)
|
||||
return;
|
||||
|
||||
GDK_GL_CONTEXT_GET_CLASS (context)->update (context, 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.14
|
||||
*/
|
||||
void
|
||||
gdk_gl_context_clear_current (void)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
|
||||
gdk_display_make_gl_context_current (display, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_get_current:
|
||||
*
|
||||
* Retrieves the current #GdkGLContext.
|
||||
*
|
||||
* Returns: (transfer none): the current #GdkGLContext, or %NULL
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkGLContext *
|
||||
gdk_gl_context_get_current (void)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
|
||||
return gdk_display_get_current_gl_context (display);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_gl_context_get_swap_interval:
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Retrieves the swap interval of the context.
|
||||
*
|
||||
* Returns: the swap interval
|
||||
*/
|
||||
gboolean
|
||||
gdk_gl_context_get_swap_interval (GdkGLContext *context)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
return priv->swap_interval;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_window_has_gl_context:
|
||||
* @window: a #GdkWindow
|
||||
*
|
||||
* Checks whether a #GdkWindow has a #GdkGLContext associated to it.
|
||||
*
|
||||
* Returns: %TRUE if the window has a GL context
|
||||
*/
|
||||
gboolean
|
||||
gdk_window_has_gl_context (GdkWindow *window)
|
||||
{
|
||||
return g_object_get_data (G_OBJECT (window), "-gdk-gl-context") != NULL;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_window_set_gl_context:
|
||||
* @window: a #GdkWindow
|
||||
* @context: a #GdkGLContext
|
||||
*
|
||||
* Sets a back pointer to a #GdkGLContext on @window.
|
||||
*
|
||||
* This function should only be called by gdk_gl_context_set_window().
|
||||
*/
|
||||
void
|
||||
gdk_window_set_gl_context (GdkWindow *window,
|
||||
GdkGLContext *context)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (window), "-gdk-gl-context", context);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_window_get_gl_context:
|
||||
* @window: a #GdkWindow
|
||||
*
|
||||
* Retrieves a pointer to the #GdkGLContext associated to
|
||||
* the @window.
|
||||
*
|
||||
* Returns: (transfer none): a #GdkGLContext, or %NULL
|
||||
*/
|
||||
GdkGLContext *
|
||||
gdk_window_get_gl_context (GdkWindow *window)
|
||||
{
|
||||
return g_object_get_data (G_OBJECT (window), "-gdk-gl-context");
|
||||
}
|
66
gdk/gdkglcontext.h
Normal file
66
gdk/gdkglcontext.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglcontext.h: 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_GL_CONTEXT_H__
|
||||
#define __GDK_GL_CONTEXT_H__
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
#include <gdk/gdktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_GL_CONTEXT (gdk_gl_context_get_type ())
|
||||
#define GDK_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_GL_CONTEXT, GdkGLContext))
|
||||
#define GDK_IS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_GL_CONTEXT))
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GType gdk_gl_context_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkDisplay * gdk_gl_context_get_display (GdkGLContext *context);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkGLPixelFormat * gdk_gl_context_get_pixel_format (GdkGLContext *context);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkVisual * gdk_gl_context_get_visual (GdkGLContext *context);
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
void gdk_gl_context_flush_buffer (GdkGLContext *context);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gboolean gdk_gl_context_make_current (GdkGLContext *context);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
void gdk_gl_context_set_window (GdkGLContext *context,
|
||||
GdkWindow *window);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkWindow * gdk_gl_context_get_window (GdkGLContext *context);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
void gdk_gl_context_update (GdkGLContext *context);
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
void gdk_gl_context_clear_current (void);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkGLContext * gdk_gl_context_get_current (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_GL_CONTEXT_H__ */
|
54
gdk/gdkglcontextprivate.h
Normal file
54
gdk/gdkglcontextprivate.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglcontextprivate.h: 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_GL_CONTEXT_PRIVATE_H__
|
||||
#define __GDK_GL_CONTEXT_PRIVATE_H__
|
||||
|
||||
#include "gdkglcontext.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GL_CONTEXT, GdkGLContextClass))
|
||||
#define GDK_IS_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GL_CONTEXT))
|
||||
#define GDK_GL_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GL_CONTEXT, GdkGLContextClass))
|
||||
|
||||
typedef struct _GdkGLContextClass GdkGLContextClass;
|
||||
|
||||
struct _GdkGLContext
|
||||
{
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
struct _GdkGLContextClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* set_window) (GdkGLContext *context,
|
||||
GdkWindow *window);
|
||||
void (* update) (GdkGLContext *context,
|
||||
GdkWindow *window);
|
||||
void (* flush_buffer) (GdkGLContext *context);
|
||||
};
|
||||
|
||||
gboolean gdk_gl_context_get_swap_interval (GdkGLContext *context);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_GL_CONTEXT_PRIVATE_H__ */
|
664
gdk/gdkglpixelformat.c
Normal file
664
gdk/gdkglpixelformat.c
Normal file
@@ -0,0 +1,664 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglpixelformat.c: GL pixel formats
|
||||
*
|
||||
* 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:gdkglpixelformat
|
||||
* @Title: GdkGLPixelFormat
|
||||
* @Short_description: Specify the pixel format for GL contexts
|
||||
*
|
||||
* The #GdkGLPixelFormat class is used to specify the types and sizes of
|
||||
* buffers to be used by a #GdkGLContext, as well as other configuration
|
||||
* parameters.
|
||||
*
|
||||
* Once created, a #GdkGLPixelFormat is immutable, and can only be used
|
||||
* to create a #GdkGLContext, or for validation.
|
||||
*
|
||||
* Once a #GdkGLPixelFormat has been validated, either directly through
|
||||
* gdk_display_validate_gl_pixel_format() or indirectly through the
|
||||
* creation of a #GdkGLContext, it is possible to query its properties
|
||||
* for the values found during validation.
|
||||
*
|
||||
* ## Using GdkGLPixelFormat ##
|
||||
*
|
||||
* Typically, you will create a new #GdkGLPixelFormat using the given
|
||||
* constructor and properties:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* GdkGLPixelFormat *format;
|
||||
*
|
||||
* // Ask for a pixel format with double buffering and
|
||||
* // a depth buffer with a size of 32 bits
|
||||
* format = gdk_gl_pixel_format_new ("double-buffer", TRUE,
|
||||
* "depth-size", 32,
|
||||
* NULL);
|
||||
* ]|
|
||||
*
|
||||
* After creating a pixel format, you can validate it using a #GdkDisplay
|
||||
* and use the result of gdk_display_validate_gl_pixel_format() to provide
|
||||
* an alternative pixel format:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* GError *error = NULL;
|
||||
* GdkGLPixelFormat *valid = NULL;
|
||||
*
|
||||
* // The "display" variable is set elsewhere.
|
||||
* // The "format" variable is the one we set previously.
|
||||
* if (!gdk_display_validate_gl_pixel_format (display, format, &valid, &error))
|
||||
* {
|
||||
* // print "error" or create a new pixel format to validate
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* You can also create a #GdkGLContext for the given display and
|
||||
* pixel format:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* GdkGLContext *context;
|
||||
* GError *error = NULL;
|
||||
*
|
||||
* context = gdk_display_create_gl_context (display, format, &error);
|
||||
* if (error != NULL)
|
||||
* {
|
||||
* // print error
|
||||
* }
|
||||
*
|
||||
* g_object_unref (format);
|
||||
* ]|
|
||||
*
|
||||
* Once a #GdkGLContext has been created with a #GdkGLPixelFormat, the
|
||||
* context will acquire a reference on the pixel format, so it's safe to
|
||||
* release the reference created at construction.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "gdkglpixelformatprivate.h"
|
||||
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkenumtypes.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
/* bool */
|
||||
PROP_DOUBLE_BUFFER,
|
||||
PROP_MULTI_SAMPLE,
|
||||
PROP_STEREO,
|
||||
|
||||
/* uint */
|
||||
PROP_AUX_BUFFERS,
|
||||
PROP_COLOR_SIZE,
|
||||
PROP_ALPHA_SIZE,
|
||||
PROP_DEPTH_SIZE,
|
||||
PROP_STENCIL_SIZE,
|
||||
PROP_ACCUM_SIZE,
|
||||
PROP_SAMPLE_BUFFERS,
|
||||
PROP_SAMPLES,
|
||||
|
||||
/* enum */
|
||||
PROP_PROFILE,
|
||||
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[LAST_PROP] = { NULL, };
|
||||
|
||||
G_DEFINE_QUARK (gdk-gl-pixel-format-error-quark, gdk_gl_pixel_format_error)
|
||||
|
||||
G_DEFINE_TYPE (GdkGLPixelFormat, gdk_gl_pixel_format, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gdk_gl_pixel_format_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkGLPixelFormat *self = GDK_GL_PIXEL_FORMAT (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOUBLE_BUFFER:
|
||||
self->double_buffer = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_MULTI_SAMPLE:
|
||||
self->multi_sample = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_STEREO:
|
||||
self->stereo = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_AUX_BUFFERS:
|
||||
self->aux_buffers = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_COLOR_SIZE:
|
||||
self->color_size = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_ALPHA_SIZE:
|
||||
self->alpha_size = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_DEPTH_SIZE:
|
||||
self->depth_size = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_STENCIL_SIZE:
|
||||
self->stencil_size = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_ACCUM_SIZE:
|
||||
self->accum_size = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_BUFFERS:
|
||||
self->sample_buffers = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLES:
|
||||
self->samples = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_PROFILE:
|
||||
self->profile = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_pixel_format_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkGLPixelFormat *self = GDK_GL_PIXEL_FORMAT (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOUBLE_BUFFER:
|
||||
g_value_set_boolean (value, self->double_buffer);
|
||||
break;
|
||||
|
||||
case PROP_MULTI_SAMPLE:
|
||||
g_value_set_boolean (value, self->multi_sample);
|
||||
break;
|
||||
|
||||
case PROP_STEREO:
|
||||
g_value_set_boolean (value, self->stereo);
|
||||
break;
|
||||
|
||||
case PROP_AUX_BUFFERS:
|
||||
g_value_set_int (value, self->aux_buffers);
|
||||
break;
|
||||
|
||||
case PROP_COLOR_SIZE:
|
||||
g_value_set_int (value, self->color_size);
|
||||
break;
|
||||
|
||||
case PROP_ALPHA_SIZE:
|
||||
g_value_set_int (value, self->alpha_size);
|
||||
break;
|
||||
|
||||
case PROP_DEPTH_SIZE:
|
||||
g_value_set_int (value, self->depth_size);
|
||||
break;
|
||||
|
||||
case PROP_STENCIL_SIZE:
|
||||
g_value_set_int (value, self->stencil_size);
|
||||
break;
|
||||
|
||||
case PROP_ACCUM_SIZE:
|
||||
g_value_set_int (value, self->accum_size);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_BUFFERS:
|
||||
g_value_set_int (value, self->sample_buffers);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLES:
|
||||
g_value_set_int (value, self->samples);
|
||||
break;
|
||||
|
||||
case PROP_PROFILE:
|
||||
g_value_set_enum (value, self->profile);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_pixel_format_class_init (GdkGLPixelFormatClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gdk_gl_pixel_format_set_property;
|
||||
gobject_class->get_property = gdk_gl_pixel_format_get_property;
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:double-buffer:
|
||||
*
|
||||
* Whether the pixel format should enable double buffering.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_DOUBLE_BUFFER] =
|
||||
g_param_spec_boolean ("double-buffer",
|
||||
P_("Double Buffer"),
|
||||
P_("Whether the pixel format should ask for double buffering"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:multi-sample:
|
||||
*
|
||||
* Whether the pixel format should enable multi-sampling.
|
||||
*
|
||||
* See also the #GdkGLPixelFormat:sample-buffers and
|
||||
* #GdkGLPixelFormat:samples properties.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_MULTI_SAMPLE] =
|
||||
g_param_spec_boolean ("multi-sample",
|
||||
P_("Multi Sample"),
|
||||
P_("Whether the pixel format should enable multi-sampling"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:stereo:
|
||||
*
|
||||
* Whether the pixel format should support stereoscopic buffers.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_STEREO] =
|
||||
g_param_spec_boolean ("stereo",
|
||||
P_("Stereo"),
|
||||
P_("Whether the pixel format should support stereoscopic buffers"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:aux-buffers:
|
||||
*
|
||||
* A positive integer indicating the number of auxiliary buffers
|
||||
* for the pixel format.
|
||||
*
|
||||
* If set to -1, the default will be used.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_AUX_BUFFERS] =
|
||||
g_param_spec_int ("aux-buffers",
|
||||
P_("Auxiliary Buffers"),
|
||||
P_("The number of auxiliary buffers"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:color-size:
|
||||
*
|
||||
* A positive integer indicating the size of each color buffer.
|
||||
*
|
||||
* If set to -1, the default will be used.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_COLOR_SIZE] =
|
||||
g_param_spec_int ("color-size",
|
||||
P_("Color Size"),
|
||||
P_("The size of each color buffer"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:alpha-size:
|
||||
*
|
||||
* A positive integer indicating the size of the alpha buffer.
|
||||
*
|
||||
* If set to 0, the alpha channel will be ignored.
|
||||
*
|
||||
* If set the -1, the default will be used.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_ALPHA_SIZE] =
|
||||
g_param_spec_int ("alpha-size",
|
||||
P_("Alpha Size"),
|
||||
P_("The size of the alpha buffer"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:depth-size:
|
||||
*
|
||||
* A positive integer indicating the size of the depth buffer.
|
||||
*
|
||||
* If set to -1, the default will be used.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_DEPTH_SIZE] =
|
||||
g_param_spec_int ("depth-size",
|
||||
P_("Depth Size"),
|
||||
P_("The size of the depth buffer"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:stencil-size:
|
||||
*
|
||||
* A positive integer indicating the size of the stencil buffer.
|
||||
*
|
||||
* If set to -1, the default will be used.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_STENCIL_SIZE] =
|
||||
g_param_spec_int ("stencil-size",
|
||||
P_("Stencil Size"),
|
||||
P_("The size of the stencil buffer"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:accum-size:
|
||||
*
|
||||
* A positive integer indicating the size of the accumulation buffer.
|
||||
*
|
||||
* If set to -1, the default will be used.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_ACCUM_SIZE] =
|
||||
g_param_spec_int ("accum-size",
|
||||
P_("Accumulation Size"),
|
||||
P_("The size of the accumulation buffer"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:sample-buffers:
|
||||
*
|
||||
* A positive integer indicating the number of multi-sample buffers.
|
||||
*
|
||||
* If set to -1, the default will be used.
|
||||
*
|
||||
* This property is only used if #GdkGLPixelFormat:multi-sample is set
|
||||
* to %TRUE.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_SAMPLE_BUFFERS] =
|
||||
g_param_spec_int ("sample-buffers",
|
||||
P_("Sample Buffers"),
|
||||
P_("The number of multi-sample buffers"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:samples:
|
||||
*
|
||||
* A positive integer indicating the number of samples for each
|
||||
* multi-sample buffer.
|
||||
*
|
||||
* If set to -1, the default will be used.
|
||||
*
|
||||
* This property is only used if #GdkGLPixelFormat:multi-sample is set
|
||||
* to %TRUE.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_SAMPLES] =
|
||||
g_param_spec_int ("samples",
|
||||
P_("Samples"),
|
||||
P_(""),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormat:profile:
|
||||
*
|
||||
* The GL profile to be used when creating a #GdkGLContext.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_PROFILE] =
|
||||
g_param_spec_enum ("profile",
|
||||
P_("Profile"),
|
||||
P_(""),
|
||||
GDK_TYPE_GL_PIXEL_FORMAT_PROFILE,
|
||||
GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, LAST_PROP, obj_props);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_pixel_format_init (GdkGLPixelFormat *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_new:
|
||||
* @first_property: the first property to set
|
||||
* @...: the value of the @first_property, followed by a %NULL terminated
|
||||
* set of property, value pairs
|
||||
*
|
||||
* Creates a new #GdkGLPixelFormat with the given list of properties.
|
||||
*
|
||||
* Returns: the newly created #GdkGLPixelFormat
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkGLPixelFormat *
|
||||
gdk_gl_pixel_format_new (const char *first_property,
|
||||
...)
|
||||
{
|
||||
GdkGLPixelFormat *res;
|
||||
va_list args;
|
||||
|
||||
va_start (args, first_property);
|
||||
|
||||
res = (GdkGLPixelFormat *) g_object_new_valist (GDK_TYPE_GL_PIXEL_FORMAT, first_property, args);
|
||||
|
||||
va_end (args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define GDK_GL_PIXEL_FORMAT_GET(CType,FieldName,DefaultValue) \
|
||||
CType \
|
||||
gdk_gl_pixel_format_get_ ## FieldName (GdkGLPixelFormat *format) \
|
||||
{ \
|
||||
g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (format), DefaultValue); \
|
||||
\
|
||||
return format->FieldName; \
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_double_buffer:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:double-buffer property.
|
||||
*
|
||||
* Returns: %TRUE if the pixel format is double buffered
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gboolean, double_buffer, FALSE)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_multi_sample:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:multi-sample property.
|
||||
*
|
||||
* Returns: %TRUE if the pixel format supports multi-sampling
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gboolean, multi_sample, FALSE)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_stereo:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:stereo property.
|
||||
*
|
||||
* Returns: %TRUE if the pixel format supports stereoscopic buffers
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gboolean, stereo, FALSE)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_color_size:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:color-size property.
|
||||
*
|
||||
* Returns: the size of the RGB components of the color buffer
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, color_size, 0)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_alpha_size:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:alpha-size property.
|
||||
*
|
||||
* Returns: the size of the alpha component of the color buffer
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, alpha_size, 0)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_depth_size:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:depth-size property.
|
||||
*
|
||||
* Returns: the size of the depth buffer
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, depth_size, 0)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_stencil_size:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:stencil-size property.
|
||||
*
|
||||
* Returns: the size of the stencil buffer
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, stencil_size, 0)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_aux_buffers:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:aux-buffers property.
|
||||
*
|
||||
* Returns: the number of auxiliary buffers.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, aux_buffers, 0);
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_accum_size:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:accum-size property.
|
||||
*
|
||||
* Returns: the size of the accumulation buffers
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, accum_size, 0)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_sample_buffers:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:sample-buffers property.
|
||||
*
|
||||
* Returns: the number of multi-sample buffers
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, sample_buffers, 0)
|
||||
|
||||
/**
|
||||
* gdk_gl_pixel_format_get_samples:
|
||||
* @format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Retrieves the value of the #GdkGLPixelFormat:samples property.
|
||||
*
|
||||
* Returns: the number of samples for each multi-sample buffer
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GDK_GL_PIXEL_FORMAT_GET (gint, samples, 0)
|
||||
|
||||
#undef GDK_GL_PIXEL_FORMAT_GET
|
75
gdk/gdkglpixelformat.h
Normal file
75
gdk/gdkglpixelformat.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglpixelformat.h: GL pixel formats
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_GL_PIXEL_FORMAT_H__
|
||||
#define __GDK_GL_PIXEL_FORMAT_H__
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
#include <gdk/gdktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_GL_PIXEL_FORMAT (gdk_gl_pixel_format_get_type ())
|
||||
#define GDK_GL_PIXEL_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_GL_PIXEL_FORMAT, GdkGLPixelFormat))
|
||||
#define GDK_IS_GL_PIXEL_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_GL_PIXEL_FORMAT))
|
||||
|
||||
#define GDK_GL_PIXEL_FORMAT_ERROR (gdk_gl_pixel_format_error_quark ())
|
||||
|
||||
typedef struct _GdkGLPixelFormatClass GdkGLPixelFormatClass;
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GType gdk_gl_pixel_format_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GQuark gdk_gl_pixel_format_error_quark (void);
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkGLPixelFormat * gdk_gl_pixel_format_new (const char *first_property,
|
||||
...);
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gboolean gdk_gl_pixel_format_get_double_buffer (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gboolean gdk_gl_pixel_format_get_multi_sample (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gboolean gdk_gl_pixel_format_get_stereo (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_color_size (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_alpha_size (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_depth_size (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_stencil_size (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_accum_size (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_aux_buffers (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_sample_buffers (GdkGLPixelFormat *format);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gint gdk_gl_pixel_format_get_samples (GdkGLPixelFormat *format);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_GL_PIXEL_FORMAT_H__ */
|
59
gdk/gdkglpixelformatprivate.h
Normal file
59
gdk/gdkglpixelformatprivate.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglpixelformatprivate.h: GL pixel formats private API
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_GL_PIXEL_FORMAT_PRIVATE_H__
|
||||
#define __GDK_GL_PIXEL_FORMAT_PRIVATE_H__
|
||||
|
||||
#include "gdkglpixelformat.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_GL_PIXEL_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GL_PIXEL_FORMAT, GdkGLPixelFormatClass))
|
||||
#define GDK_IS_GL_PIXEL_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GL_PIXEL_FORMAT))
|
||||
#define GDK_GL_PIXEL_FORMAT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GL_PIXEL_FORMAT, GdkGLPixelFormatClass))
|
||||
|
||||
struct _GdkGLPixelFormat
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
gboolean double_buffer;
|
||||
gboolean multi_sample;
|
||||
gboolean stereo;
|
||||
|
||||
int aux_buffers;
|
||||
int color_size;
|
||||
int alpha_size;
|
||||
int depth_size;
|
||||
int stencil_size;
|
||||
int accum_size;
|
||||
int sample_buffers;
|
||||
int samples;
|
||||
|
||||
GdkGLPixelFormatProfile profile;
|
||||
};
|
||||
|
||||
struct _GdkGLPixelFormatClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_GL_PIXEL_FORMAT_PRIVATE_H__ */
|
@@ -84,7 +84,8 @@ typedef enum {
|
||||
GDK_DEBUG_DRAW = 1 << 9,
|
||||
GDK_DEBUG_EVENTLOOP = 1 << 10,
|
||||
GDK_DEBUG_FRAMES = 1 << 11,
|
||||
GDK_DEBUG_SETTINGS = 1 << 12
|
||||
GDK_DEBUG_SETTINGS = 1 << 12,
|
||||
GDK_DEBUG_OPENGL = 1 << 13
|
||||
} GdkDebugFlag;
|
||||
|
||||
typedef enum {
|
||||
@@ -406,6 +407,11 @@ void _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_win
|
||||
gboolean _gdk_window_has_impl (GdkWindow *window);
|
||||
GdkWindow * _gdk_window_get_impl_window (GdkWindow *window);
|
||||
|
||||
gboolean gdk_window_has_gl_context (GdkWindow *window);
|
||||
void gdk_window_set_gl_context (GdkWindow *window,
|
||||
GdkGLContext *context);
|
||||
GdkGLContext * gdk_window_get_gl_context (GdkWindow *window);
|
||||
|
||||
/*****************************
|
||||
* offscreen window routines *
|
||||
*****************************/
|
||||
|
@@ -128,6 +128,9 @@ typedef struct _GdkWindow GdkWindow;
|
||||
typedef struct _GdkKeymap GdkKeymap;
|
||||
typedef struct _GdkAppLaunchContext GdkAppLaunchContext;
|
||||
|
||||
typedef struct _GdkGLPixelFormat GdkGLPixelFormat;
|
||||
typedef struct _GdkGLContext GdkGLContext;
|
||||
|
||||
/**
|
||||
* GdkByteOrder:
|
||||
* @GDK_LSB_FIRST: The values are stored with the least-significant byte
|
||||
@@ -429,8 +432,25 @@ struct _GdkPoint
|
||||
gint y;
|
||||
};
|
||||
|
||||
/**
|
||||
* GdkGLPixelFormatProfile:
|
||||
* @GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT: ...
|
||||
* @GDK_GL_PIXEL_FORMAT_PROFILE_LEGACY: ...
|
||||
* @GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE: ...
|
||||
*
|
||||
* ...
|
||||
*/
|
||||
typedef enum {
|
||||
GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT,
|
||||
GDK_GL_PIXEL_FORMAT_PROFILE_LEGACY,
|
||||
GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE
|
||||
} GdkGLPixelFormatProfile;
|
||||
|
||||
typedef enum {
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_INVALID_FORMAT,
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE
|
||||
} GdkGLPixelFormatError;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __GDK_TYPES_H__ */
|
||||
|
@@ -39,6 +39,8 @@ libgdk_x11_la_SOURCES = \
|
||||
gdkeventtranslator.c \
|
||||
gdkeventtranslator.h \
|
||||
gdkgeometry-x11.c \
|
||||
gdkglcontext-x11.c \
|
||||
gdkglcontext-x11.h \
|
||||
gdkkeys-x11.c \
|
||||
gdkmain-x11.c \
|
||||
gdkproperty-x11.c \
|
||||
@@ -71,6 +73,7 @@ libgdkx11include_HEADERS = \
|
||||
gdkx11display.h \
|
||||
gdkx11displaymanager.h \
|
||||
gdkx11dnd.h \
|
||||
gdkx11glcontext.h \
|
||||
gdkx11keys.h \
|
||||
gdkx11property.h \
|
||||
gdkx11screen.h \
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "gdkdisplay-x11.h"
|
||||
#include "gdkprivate-x11.h"
|
||||
#include "gdkscreen-x11.h"
|
||||
#include "gdkglcontext-x11.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gprintf.h>
|
||||
@@ -781,11 +782,13 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!window ||
|
||||
xevent->xconfigure.event != xevent->xconfigure.window ||
|
||||
GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
|
||||
GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
|
||||
return_val = FALSE;
|
||||
if (!window ||
|
||||
xevent->xconfigure.event != xevent->xconfigure.window ||
|
||||
GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT ||
|
||||
GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
|
||||
{
|
||||
return_val = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
event->configure.type = GDK_CONFIGURE;
|
||||
@@ -2903,5 +2906,10 @@ gdk_x11_display_class_init (GdkX11DisplayClass * class)
|
||||
display_class->text_property_to_utf8_list = _gdk_x11_display_text_property_to_utf8_list;
|
||||
display_class->utf8_to_string_target = _gdk_x11_display_utf8_to_string_target;
|
||||
|
||||
display_class->validate_gl_pixel_format = gdk_x11_display_validate_gl_pixel_format;
|
||||
display_class->create_gl_context = gdk_x11_display_create_gl_context;
|
||||
display_class->destroy_gl_context = gdk_x11_display_destroy_gl_context;
|
||||
display_class->make_gl_context_current = gdk_x11_display_make_gl_context_current;
|
||||
|
||||
_gdk_x11_windowing_init ();
|
||||
}
|
||||
|
@@ -124,6 +124,20 @@ struct _GdkX11Display
|
||||
GSList *error_traps;
|
||||
|
||||
gint wm_moveresize_button;
|
||||
|
||||
/* GLX information */
|
||||
guint have_glx : 1;
|
||||
gint glx_version;
|
||||
gint glx_error_base;
|
||||
gint glx_event_base;
|
||||
|
||||
/* GLX extensions we check */
|
||||
guint has_glx_swap_interval : 1;
|
||||
guint has_glx_create_context : 1;
|
||||
guint has_glx_texture_from_pixmap : 1;
|
||||
guint has_glx_video_sync : 1;
|
||||
guint has_glx_buffer_age : 1;
|
||||
guint has_glx_sync_control : 1;
|
||||
};
|
||||
|
||||
struct _GdkX11DisplayClass
|
||||
|
920
gdk/x11/gdkglcontext-x11.c
Normal file
920
gdk/x11/gdkglcontext-x11.c
Normal file
@@ -0,0 +1,920 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglcontext-x11.c: X11 specific OpenGL wrappers
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkglcontext-x11.h"
|
||||
#include "gdkdisplay-x11.h"
|
||||
#include "gdkscreen-x11.h"
|
||||
|
||||
#include "gdkx11display.h"
|
||||
#include "gdkx11glcontext.h"
|
||||
#include "gdkx11screen.h"
|
||||
#include "gdkx11window.h"
|
||||
#include "gdkx11visual.h"
|
||||
|
||||
#include "gdkinternals.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
#include <GL/glx.h>
|
||||
|
||||
G_DEFINE_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT)
|
||||
|
||||
typedef struct {
|
||||
GLXDrawable drawable;
|
||||
|
||||
GdkDisplay *display;
|
||||
GdkGLContext *context;
|
||||
GdkWindow *window;
|
||||
|
||||
guint32 last_frame_counter;
|
||||
} DrawableInfo;
|
||||
|
||||
static void
|
||||
drawable_info_free (gpointer data_)
|
||||
{
|
||||
DrawableInfo *data = data_;
|
||||
|
||||
gdk_x11_display_error_trap_push (data->display);
|
||||
|
||||
if (data->drawable)
|
||||
glXDestroyWindow (gdk_x11_display_get_xdisplay (data->display), data->drawable);
|
||||
|
||||
gdk_x11_display_error_trap_pop_ignored (data->display);
|
||||
|
||||
g_slice_free (DrawableInfo, data);
|
||||
}
|
||||
|
||||
static DrawableInfo *
|
||||
get_glx_drawable_info (GdkWindow *window)
|
||||
{
|
||||
return g_object_get_data (G_OBJECT (window), "-gdk-x11-window-glx-info");
|
||||
}
|
||||
|
||||
static void
|
||||
set_glx_drawable_info (GdkWindow *window,
|
||||
DrawableInfo *info)
|
||||
{
|
||||
g_object_set_data_full (G_OBJECT (window), "-gdk-x11-window-glx-info",
|
||||
info,
|
||||
drawable_info_free);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_gl_context_set_window (GdkGLContext *context,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
DrawableInfo *info;
|
||||
|
||||
if (window == NULL)
|
||||
{
|
||||
gdk_x11_display_make_gl_context_current (display, context, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we need to make sure that the GdkWindow is backed by
|
||||
* an actual native surface
|
||||
*/
|
||||
gdk_window_ensure_native (window);
|
||||
|
||||
/* GLX < 1.3 accepts X11 drawables, so there's no need to
|
||||
* go through the creation of a GLX drawable
|
||||
*/
|
||||
if (GDK_X11_DISPLAY (display)->glx_version < 13)
|
||||
return;
|
||||
|
||||
info = get_glx_drawable_info (window);
|
||||
if (info != NULL)
|
||||
return;
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
info = g_slice_new (DrawableInfo);
|
||||
info->window = window;
|
||||
info->context = context;
|
||||
info->display = display;
|
||||
info->drawable = glXCreateWindow (gdk_x11_display_get_xdisplay (display),
|
||||
context_x11->glx_config,
|
||||
gdk_x11_window_get_xid (window),
|
||||
NULL);
|
||||
info->last_frame_counter = 0;
|
||||
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
|
||||
set_glx_drawable_info (window, info);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_gl_context_update (GdkGLContext *context,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
int width, height;
|
||||
|
||||
if (!gdk_x11_display_make_gl_context_current (display, context, window))
|
||||
return;
|
||||
|
||||
width = gdk_window_get_width (window);
|
||||
height = gdk_window_get_height (window);
|
||||
|
||||
GDK_NOTE (OPENGL, g_print ("Updating GL viewport size to { %d, %d } for window %lu (context: %p)\n",
|
||||
width, height,
|
||||
(unsigned long) gdk_x11_window_get_xid (window),
|
||||
context));
|
||||
|
||||
glViewport (0, 0, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_wait_for_vblank (GdkDisplay *display,
|
||||
GLXDrawable drawable)
|
||||
{
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
Display *dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
if (display_x11->has_glx_sync_control)
|
||||
{
|
||||
gint64 ust, msc, sbc;
|
||||
|
||||
glXGetSyncValuesOML (dpy, drawable, &ust, &msc, &sbc);
|
||||
glXWaitForMscOML (dpy, drawable,
|
||||
0, 2, (msc + 1) % 2,
|
||||
&ust, &msc, &sbc);
|
||||
}
|
||||
else if (display_x11->has_glx_video_sync)
|
||||
{
|
||||
guint32 current_count;
|
||||
|
||||
glXGetVideoSyncSGI (¤t_count);
|
||||
glXWaitVideoSyncSGI (2, (current_count + 1) % 2, ¤t_count);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_gl_context_flush_buffer (GdkGLContext *context)
|
||||
{
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
GdkWindow *window = gdk_gl_context_get_window (context);
|
||||
Display *dpy = gdk_x11_display_get_xdisplay (display);
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
DrawableInfo *info;
|
||||
GLXDrawable drawable;
|
||||
|
||||
if (window == NULL)
|
||||
return;
|
||||
|
||||
gdk_x11_display_make_gl_context_current (display, context, window);
|
||||
|
||||
info = get_glx_drawable_info (window);
|
||||
if (info != NULL && info->drawable != None)
|
||||
drawable = info->drawable;
|
||||
else
|
||||
drawable = gdk_x11_window_get_xid (window);
|
||||
|
||||
GDK_NOTE (OPENGL,
|
||||
g_print ("Flushing GLX buffers for %s drawable %lu (window: %lu)\n",
|
||||
drawable == info->drawable ? "GLX" : "X11",
|
||||
(unsigned long) drawable,
|
||||
(unsigned long) gdk_x11_window_get_xid (window)));
|
||||
|
||||
/* if we are going to wait for the vertical refresh manually
|
||||
* we need to flush pending redraws, and we also need to wait
|
||||
* for that to finish, otherwise we are going to tear.
|
||||
*
|
||||
* obviously, this condition should not be hit if we have
|
||||
* GLX_SGI_swap_control, and we ask the driver to do the right
|
||||
* thing.
|
||||
*/
|
||||
{
|
||||
guint32 end_frame_counter = 0;
|
||||
gboolean has_counter = display_x11->has_glx_video_sync;
|
||||
gboolean can_wait = display_x11->has_glx_video_sync ||
|
||||
display_x11->has_glx_sync_control;
|
||||
|
||||
if (display_x11->has_glx_video_sync)
|
||||
glXGetVideoSyncSGI (&end_frame_counter);
|
||||
|
||||
if (!display_x11->has_glx_swap_interval)
|
||||
{
|
||||
glFinish ();
|
||||
|
||||
if (has_counter && can_wait)
|
||||
{
|
||||
guint32 last_counter = info != NULL ? info->last_frame_counter : 0;
|
||||
|
||||
if (last_counter == end_frame_counter)
|
||||
maybe_wait_for_vblank (display, drawable);
|
||||
}
|
||||
else if (can_wait)
|
||||
maybe_wait_for_vblank (display, drawable);
|
||||
}
|
||||
}
|
||||
|
||||
glXSwapBuffers (dpy, drawable);
|
||||
|
||||
if (info != NULL && display_x11->has_glx_video_sync)
|
||||
glXGetVideoSyncSGI (&info->last_frame_counter);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_gl_context_class_init (GdkX11GLContextClass *klass)
|
||||
{
|
||||
GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
|
||||
|
||||
context_class->set_window = gdk_x11_gl_context_set_window;
|
||||
context_class->update = gdk_x11_gl_context_update;
|
||||
context_class->flush_buffer = gdk_x11_gl_context_flush_buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_gl_context_init (GdkX11GLContext *self)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_x11_display_init_gl (GdkDisplay *display)
|
||||
{
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
GdkScreen *screen;
|
||||
Display *dpy;
|
||||
int error_base, event_base;
|
||||
int screen_num;
|
||||
|
||||
if (display_x11->have_glx)
|
||||
return TRUE;
|
||||
|
||||
dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
if (!glXQueryExtension (dpy, &error_base, &event_base))
|
||||
return FALSE;
|
||||
|
||||
screen = gdk_display_get_default_screen (display);
|
||||
screen_num = GDK_X11_SCREEN (screen)->screen_num;
|
||||
|
||||
display_x11->have_glx = TRUE;
|
||||
|
||||
display_x11->glx_version = epoxy_glx_version (dpy, screen_num);
|
||||
display_x11->glx_error_base = error_base;
|
||||
display_x11->glx_event_base = event_base;
|
||||
|
||||
display_x11->has_glx_create_context =
|
||||
epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_create_context_profile");
|
||||
display_x11->has_glx_swap_interval =
|
||||
epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_swap_control");
|
||||
display_x11->has_glx_texture_from_pixmap =
|
||||
epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_texture_from_pixmap");
|
||||
display_x11->has_glx_video_sync =
|
||||
epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_video_sync");
|
||||
display_x11->has_glx_buffer_age =
|
||||
epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_buffer_age");
|
||||
display_x11->has_glx_sync_control =
|
||||
epoxy_has_glx_extension (dpy, screen_num, "GLX_OML_sync_control");
|
||||
|
||||
GDK_NOTE (OPENGL,
|
||||
g_print ("GLX version %d.%d found\n"
|
||||
" - Vendor: %s\n"
|
||||
" - Checked extensions:\n"
|
||||
"\t* GLX_ARB_create_context_profile: %s\n"
|
||||
"\t* GLX_SGI_swap_control: %s\n"
|
||||
"\t* GLX_EXT_texture_from_pixmap: %s\n"
|
||||
"\t* GLX_SGI_video_sync: %s\n"
|
||||
"\t* GLX_EXT_buffer_age: %s\n"
|
||||
"\t* GLX_OML_sync_control: %s\n",
|
||||
display_x11->glx_version / 10,
|
||||
display_x11->glx_version % 10,
|
||||
glXGetClientString (dpy, GLX_VENDOR),
|
||||
display_x11->has_glx_create_context ? "yes" : "no",
|
||||
display_x11->has_glx_swap_interval ? "yes" : "no",
|
||||
display_x11->has_glx_texture_from_pixmap ? "yes" : "no",
|
||||
display_x11->has_glx_video_sync ? "yes" : "no",
|
||||
display_x11->has_glx_buffer_age ? "yes" : "no",
|
||||
display_x11->has_glx_sync_control ? "yes" : "no"));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define MAX_GLX_ATTRS 30
|
||||
|
||||
static void
|
||||
get_glx_attributes_for_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
int *attrs)
|
||||
{
|
||||
GdkX11Display *display_x11;
|
||||
int i = 0;
|
||||
|
||||
attrs[i++] = GLX_DRAWABLE_TYPE;
|
||||
attrs[i++] = GLX_WINDOW_BIT;
|
||||
|
||||
attrs[i++] = GLX_RENDER_TYPE;
|
||||
attrs[i++] = GLX_RGBA_BIT;
|
||||
|
||||
if (format->double_buffer)
|
||||
{
|
||||
attrs[i++] = GLX_DOUBLEBUFFER;
|
||||
attrs[i++] = GL_TRUE;
|
||||
}
|
||||
|
||||
if (format->stereo)
|
||||
{
|
||||
attrs[i++] = GLX_STEREO;
|
||||
attrs[i++] = GL_TRUE;
|
||||
}
|
||||
|
||||
if (format->color_size < 0)
|
||||
{
|
||||
attrs[i++] = GLX_RED_SIZE;
|
||||
attrs[i++] = 1;
|
||||
attrs[i++] = GLX_GREEN_SIZE;
|
||||
attrs[i++] = 1;
|
||||
attrs[i++] = GLX_BLUE_SIZE;
|
||||
attrs[i++] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs[i++] = GLX_RED_SIZE;
|
||||
attrs[i++] = format->color_size;
|
||||
attrs[i++] = GLX_GREEN_SIZE;
|
||||
attrs[i++] = format->color_size;
|
||||
attrs[i++] = GLX_BLUE_SIZE;
|
||||
attrs[i++] = format->color_size;
|
||||
}
|
||||
|
||||
if (format->alpha_size < 0)
|
||||
{
|
||||
attrs[i++] = GLX_ALPHA_SIZE;
|
||||
attrs[i++] = 1;
|
||||
}
|
||||
else if (format->alpha_size == 0)
|
||||
{
|
||||
attrs[i++] = GLX_ALPHA_SIZE;
|
||||
attrs[i++] = GLX_DONT_CARE;
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs[i++] = GLX_ALPHA_SIZE;
|
||||
attrs[i++] = format->alpha_size;
|
||||
}
|
||||
|
||||
if (format->depth_size < 0)
|
||||
{
|
||||
attrs[i++] = GLX_DEPTH_SIZE;
|
||||
attrs[i++] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs[i++] = GLX_DEPTH_SIZE;
|
||||
attrs[i++] = format->depth_size;
|
||||
}
|
||||
|
||||
if (format->stencil_size < 0)
|
||||
{
|
||||
attrs[i++] = GLX_STENCIL_SIZE;
|
||||
attrs[i++] = GLX_DONT_CARE;
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs[i++] = GLX_STENCIL_SIZE;
|
||||
attrs[i++] = format->stencil_size;
|
||||
}
|
||||
|
||||
if (format->accum_size > 0)
|
||||
{
|
||||
attrs[i++] = GLX_ACCUM_RED_SIZE;
|
||||
attrs[i++] = format->accum_size;
|
||||
attrs[i++] = GLX_ACCUM_GREEN_SIZE;
|
||||
attrs[i++] = format->accum_size;
|
||||
attrs[i++] = GLX_ACCUM_BLUE_SIZE;
|
||||
attrs[i++] = format->accum_size;
|
||||
attrs[i++] = GLX_ACCUM_ALPHA_SIZE;
|
||||
attrs[i++] = format->accum_size;
|
||||
}
|
||||
|
||||
display_x11 = GDK_X11_DISPLAY (display);
|
||||
if (display_x11->glx_version >= 14 && format->multi_sample)
|
||||
{
|
||||
attrs[i++] = GLX_SAMPLE_BUFFERS;
|
||||
attrs[i++] = format->sample_buffers > 0 ? format->sample_buffers : 1;
|
||||
|
||||
attrs[i++] = GLX_SAMPLES;
|
||||
attrs[i++] = format->samples > 0 ? format->samples : 1;
|
||||
}
|
||||
|
||||
attrs[i++] = None;
|
||||
|
||||
g_assert (i < MAX_GLX_ATTRS);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
find_fbconfig_for_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GLXFBConfig *fb_config_out,
|
||||
XVisualInfo **visinfo_out,
|
||||
GError **error)
|
||||
{
|
||||
static int attrs[MAX_GLX_ATTRS];
|
||||
|
||||
Display *dpy = gdk_x11_display_get_xdisplay (display);
|
||||
GLXFBConfig *configs;
|
||||
int n_configs, i;
|
||||
gboolean use_rgba;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
get_glx_attributes_for_pixel_format (display, format, attrs);
|
||||
|
||||
use_rgba = format->alpha_size != 0;
|
||||
|
||||
configs = glXChooseFBConfig (dpy, DefaultScreen (dpy), attrs, &n_configs);
|
||||
if (configs == NULL || n_configs == 0)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
|
||||
_("No available configurations for the given pixel format"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* if we don't care about an alpha channel, then the first
|
||||
* valid configuration is the one we give back
|
||||
*/
|
||||
if (!use_rgba)
|
||||
{
|
||||
if (fb_config_out != NULL)
|
||||
*fb_config_out = configs[0];
|
||||
|
||||
if (visinfo_out != NULL)
|
||||
*visinfo_out = glXGetVisualFromFBConfig (dpy, configs[0]);
|
||||
|
||||
retval = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_configs; i++)
|
||||
{
|
||||
XVisualInfo *visinfo;
|
||||
unsigned long mask;
|
||||
|
||||
visinfo = glXGetVisualFromFBConfig (dpy, configs[i]);
|
||||
if (visinfo == NULL)
|
||||
continue;
|
||||
|
||||
mask = visinfo->red_mask | visinfo->green_mask | visinfo->blue_mask;
|
||||
if (visinfo->depth == 32 && mask != 0xffffffff)
|
||||
{
|
||||
if (fb_config_out != NULL)
|
||||
*fb_config_out = configs[i];
|
||||
|
||||
if (visinfo_out != NULL)
|
||||
*visinfo_out = visinfo;
|
||||
|
||||
retval = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
XFree (visinfo);
|
||||
}
|
||||
|
||||
g_set_error (error, GDK_GL_PIXEL_FORMAT_ERROR,
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
|
||||
_("No available configurations for the given RGBA pixel format"));
|
||||
|
||||
out:
|
||||
XFree (configs);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
update_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GLXFBConfig config)
|
||||
{
|
||||
Display *dpy = gdk_x11_display_get_xdisplay (display);
|
||||
int value = 0;
|
||||
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_DOUBLEBUFFER, &format->double_buffer);
|
||||
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_RED_SIZE, &value);
|
||||
format->color_size = value;
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_GREEN_SIZE, &value);
|
||||
format->color_size = MIN (format->color_size, value);
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_BLUE_SIZE, &value);
|
||||
format->color_size = MIN (format->color_size, value);
|
||||
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_ALPHA_SIZE, &format->alpha_size);
|
||||
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_AUX_BUFFERS, &format->aux_buffers);
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_DEPTH_SIZE, &format->depth_size);
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_STENCIL_SIZE, &format->stencil_size);
|
||||
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_ACCUM_RED_SIZE, &value);
|
||||
format->accum_size = value;
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_ACCUM_GREEN_SIZE, &value);
|
||||
format->accum_size = MIN (format->accum_size, value);
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_ACCUM_BLUE_SIZE, &value);
|
||||
format->accum_size = MIN (format->accum_size, value);
|
||||
glXGetFBConfigAttrib (dpy, config, GLX_ACCUM_ALPHA_SIZE, &value);
|
||||
format->accum_size = MIN (format->accum_size, value);
|
||||
}
|
||||
|
||||
static GLXContext
|
||||
create_gl3_context (GdkDisplay *display,
|
||||
GLXFBConfig config,
|
||||
GdkGLContext *share)
|
||||
{
|
||||
static const int attrib_list[] = {
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||
None,
|
||||
};
|
||||
|
||||
GdkX11GLContext *context_x11 = NULL;
|
||||
|
||||
if (share != NULL)
|
||||
context_x11 = GDK_X11_GL_CONTEXT (share);
|
||||
|
||||
return glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
|
||||
config,
|
||||
context_x11 != NULL ? context_x11->glx_context : NULL,
|
||||
True,
|
||||
attrib_list);
|
||||
}
|
||||
|
||||
static GLXContext
|
||||
create_gl_context (GdkDisplay *display,
|
||||
GLXFBConfig config,
|
||||
GdkGLContext *share)
|
||||
{
|
||||
GdkX11GLContext *context_x11 = NULL;
|
||||
|
||||
if (share != NULL)
|
||||
context_x11 = GDK_X11_GL_CONTEXT (share);
|
||||
|
||||
return glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
|
||||
config,
|
||||
GLX_RGBA_TYPE,
|
||||
context_x11 != NULL ? context_x11->glx_context : NULL,
|
||||
True);
|
||||
}
|
||||
|
||||
GdkGLContext *
|
||||
gdk_x11_display_create_gl_context (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLContext *share,
|
||||
GError **error)
|
||||
{
|
||||
GdkGLPixelFormat *valid_format;
|
||||
GdkX11GLContext *context;
|
||||
GdkVisual *gdk_visual;
|
||||
GLXFBConfig config;
|
||||
GLXContext glx_context;
|
||||
Window dummy_xwin;
|
||||
GLXWindow dummy_glx;
|
||||
GLXWindow dummy_drawable;
|
||||
gboolean is_direct;
|
||||
XVisualInfo *xvisinfo;
|
||||
XSetWindowAttributes attrs;
|
||||
unsigned long mask;
|
||||
Display *dpy;
|
||||
|
||||
if (!gdk_x11_display_validate_gl_pixel_format (display, format, NULL, error))
|
||||
return NULL;
|
||||
|
||||
/* if validation succeeded, then we don't need to check for the
|
||||
* result here: we know the pixel format has a valid GLXFBConfig
|
||||
*/
|
||||
find_fbconfig_for_pixel_format (display, format, &config, &xvisinfo, NULL);
|
||||
|
||||
dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
/* we check for the GLX_ARB_create_context_profile extension
|
||||
* while validating the PixelFormat.
|
||||
*/
|
||||
if (format->profile == GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE)
|
||||
glx_context = create_gl3_context (display, config, share);
|
||||
else
|
||||
{
|
||||
/* GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT is currently
|
||||
* equivalent to the LEGACY profile
|
||||
*/
|
||||
glx_context = create_gl_context (display, config, share);
|
||||
}
|
||||
|
||||
if (glx_context == NULL)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
|
||||
_("Unable to create a GL context"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
is_direct = glXIsDirect (dpy, glx_context);
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
/* create a dummy window; this is needed because GLX does not allow
|
||||
* us to query the context until it's bound to a drawable; we simply
|
||||
* create a small OR window, put it off screen, and never map it. in
|
||||
* order to keep the GL machinery in a sane state, we always make
|
||||
* the dummy window the current drawable if the user unsets the
|
||||
* GdkWindow bound to the GdkGLContext.
|
||||
*/
|
||||
attrs.override_redirect = True;
|
||||
attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
|
||||
attrs.border_pixel = 0;
|
||||
mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
|
||||
|
||||
dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
|
||||
-100, -100, 1, 1,
|
||||
0,
|
||||
xvisinfo->depth,
|
||||
CopyFromParent,
|
||||
xvisinfo->visual,
|
||||
mask,
|
||||
&attrs);
|
||||
|
||||
/* GLX API introduced in 1.3 expects GLX drawables */
|
||||
if (GDK_X11_DISPLAY (display)->glx_version >= 13)
|
||||
dummy_glx = glXCreateWindow (dpy, config, dummy_xwin, NULL);
|
||||
else
|
||||
dummy_glx = None;
|
||||
|
||||
dummy_drawable = dummy_glx != None
|
||||
? dummy_glx
|
||||
: dummy_xwin;
|
||||
|
||||
glXMakeContextCurrent (dpy, dummy_drawable, dummy_drawable, glx_context);
|
||||
|
||||
gdk_visual = gdk_x11_screen_lookup_visual (gdk_display_get_default_screen (display),
|
||||
xvisinfo->visualid);
|
||||
|
||||
XFree (xvisinfo);
|
||||
|
||||
if (gdk_x11_display_error_trap_pop (display))
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
|
||||
_("Unable to create a GL context"));
|
||||
|
||||
glXDestroyContext (dpy, glx_context);
|
||||
|
||||
if (dummy_xwin)
|
||||
XDestroyWindow (dpy, dummy_xwin);
|
||||
if (dummy_glx)
|
||||
glXDestroyWindow (dpy, dummy_glx);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GDK_NOTE (OPENGL,
|
||||
g_print ("Created GLX context[%p], %s, dummy drawable: %lu\n",
|
||||
glx_context,
|
||||
is_direct ? "direct" : "indirect",
|
||||
(unsigned long) dummy_xwin));
|
||||
|
||||
/* the GdkGLContext holds a reference on the pixel format
|
||||
* that is used to create it, not the one that the user
|
||||
* passed; this allows the user to query the pixel format
|
||||
* attributes
|
||||
*/
|
||||
valid_format = g_object_new (GDK_TYPE_GL_PIXEL_FORMAT, NULL);
|
||||
update_pixel_format (display, valid_format, config);
|
||||
|
||||
context = g_object_new (GDK_X11_TYPE_GL_CONTEXT,
|
||||
"display", display,
|
||||
"pixel-format", valid_format,
|
||||
"visual", gdk_visual,
|
||||
NULL);
|
||||
|
||||
context->glx_config = config;
|
||||
context->glx_context = glx_context;
|
||||
context->dummy_drawable = dummy_xwin;
|
||||
context->dummy_glx_drawable = dummy_glx;
|
||||
context->current_drawable = dummy_drawable;
|
||||
context->is_direct = is_direct;
|
||||
|
||||
g_object_unref (valid_format);
|
||||
|
||||
return GDK_GL_CONTEXT (context);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_x11_display_destroy_gl_context (GdkDisplay *display,
|
||||
GdkGLContext *context)
|
||||
{
|
||||
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
|
||||
Display *dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
if (context_x11->glx_context != NULL)
|
||||
{
|
||||
if (glXGetCurrentContext () == context_x11->glx_context)
|
||||
glXMakeContextCurrent (dpy, None, None, NULL);
|
||||
|
||||
GDK_NOTE (OPENGL, g_print ("Destroying GLX context\n"));
|
||||
glXDestroyContext (dpy, context_x11->glx_context);
|
||||
context_x11->glx_context = NULL;
|
||||
}
|
||||
|
||||
if (context_x11->dummy_glx_drawable)
|
||||
{
|
||||
GDK_NOTE (OPENGL, g_print ("Destroying dummy GLX drawable\n"));
|
||||
glXDestroyWindow (dpy, context_x11->dummy_glx_drawable);
|
||||
context_x11->dummy_glx_drawable = None;
|
||||
}
|
||||
|
||||
if (context_x11->dummy_drawable)
|
||||
{
|
||||
GDK_NOTE (OPENGL, g_print ("Destroying dummy drawable\n"));
|
||||
XDestroyWindow (dpy, context_x11->dummy_drawable);
|
||||
context_x11->dummy_drawable = None;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_x11_display_make_gl_context_current (GdkDisplay *display,
|
||||
GdkGLContext *context,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
|
||||
GLXDrawable drawable = None;
|
||||
|
||||
if (context_x11->glx_context == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (window == NULL)
|
||||
{
|
||||
/* we re-bind our dummy drawable, so that the context
|
||||
* can still be used for queries
|
||||
*/
|
||||
drawable = context_x11->dummy_glx_drawable != None
|
||||
? context_x11->dummy_glx_drawable
|
||||
: context_x11->dummy_drawable;
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawableInfo *info = get_glx_drawable_info (window);
|
||||
|
||||
if (info != NULL && info->drawable != None)
|
||||
drawable = info->drawable;
|
||||
else
|
||||
drawable = gdk_x11_window_get_xid (window);
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (drawable == None))
|
||||
return FALSE;
|
||||
|
||||
if (drawable == context_x11->current_drawable)
|
||||
return TRUE;
|
||||
|
||||
GDK_NOTE (OPENGL,
|
||||
g_print ("Making GLX context current to drawable %lu (dummy: %s)\n",
|
||||
(unsigned long) drawable,
|
||||
drawable == context_x11->dummy_drawable ? "yes" : "no"));
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
glXMakeContextCurrent (gdk_x11_display_get_xdisplay (display),
|
||||
drawable, drawable,
|
||||
context_x11->glx_context);
|
||||
|
||||
if (GDK_X11_DISPLAY (display)->has_glx_swap_interval)
|
||||
{
|
||||
if (gdk_gl_context_get_swap_interval (context))
|
||||
glXSwapIntervalSGI (1);
|
||||
else
|
||||
glXSwapIntervalSGI (0);
|
||||
}
|
||||
|
||||
XSync (gdk_x11_display_get_xdisplay (display), False);
|
||||
|
||||
if (gdk_x11_display_error_trap_pop (display))
|
||||
{
|
||||
g_critical ("X Error received while calling glXMakeContextCurrent()");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
context_x11->current_drawable = drawable;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_x11_display_validate_gl_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLPixelFormat **validated_format,
|
||||
GError **error)
|
||||
{
|
||||
GLXFBConfig config;
|
||||
|
||||
if (!gdk_x11_display_init_gl (display))
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
|
||||
_("No GL implementation is available"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (format->profile == GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE)
|
||||
{
|
||||
if (!GDK_X11_DISPLAY (display)->has_glx_create_context)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
|
||||
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
|
||||
_("The GLX_ARB_create_context_profile extension "
|
||||
"needed to create 3.2 core profiles is not "
|
||||
"available"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!find_fbconfig_for_pixel_format (display, format, &config, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
GDK_NOTE (OPENGL,
|
||||
g_print ("Found GLX config for requested pixel format:\n"
|
||||
" - double-buffer: %s\n"
|
||||
" - multi-sample: %s\n"
|
||||
" - stereo: %s\n"
|
||||
" - color-size: %d, alpha-size: %d\n"
|
||||
" - depth-size: %d\n"
|
||||
" - stencil-size: %d\n"
|
||||
" - aux-buffers: %d\n"
|
||||
" - accum-size: %d\n"
|
||||
" - sample-buffers: %d, samples: %d\n",
|
||||
format->double_buffer ? "yes" : "no",
|
||||
format->multi_sample ? "yes" : "no",
|
||||
format->stereo ? "yes" : "no",
|
||||
format->color_size, format->alpha_size,
|
||||
format->depth_size,
|
||||
format->stencil_size,
|
||||
format->aux_buffers,
|
||||
format->accum_size,
|
||||
format->sample_buffers, format->samples));
|
||||
|
||||
if (validated_format != NULL)
|
||||
{
|
||||
GdkGLPixelFormat *valid = g_object_new (GDK_TYPE_GL_PIXEL_FORMAT, NULL);
|
||||
|
||||
/* update the pixel format with the values of the
|
||||
* configuration we found
|
||||
*/
|
||||
update_pixel_format (display, valid, config);
|
||||
|
||||
*validated_format = valid;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_x11_display_get_glx_version:
|
||||
* @display: a #GdkDisplay
|
||||
* @major: (out): return location for the GLX major version
|
||||
* @minor: (out): return location for the GLX minor version
|
||||
*
|
||||
* Retrieves the version of the GLX implementation.
|
||||
*
|
||||
* Returns: %TRUE if GLX is available
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
gboolean
|
||||
gdk_x11_display_get_glx_version (GdkDisplay *display,
|
||||
int *major,
|
||||
int *minor)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
|
||||
if (!GDK_IS_X11_DISPLAY (display))
|
||||
return FALSE;
|
||||
|
||||
if (!gdk_x11_display_init_gl (display))
|
||||
return FALSE;
|
||||
|
||||
if (major != NULL)
|
||||
*major = GDK_X11_DISPLAY (display)->glx_version / 10;
|
||||
if (minor != NULL)
|
||||
*minor = GDK_X11_DISPLAY (display)->glx_version % 10;
|
||||
|
||||
return TRUE;
|
||||
}
|
78
gdk/x11/gdkglcontext-x11.h
Normal file
78
gdk/x11/gdkglcontext-x11.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglcontext-x11.h: Private X11 specific OpenGL wrappers
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_X11_GL_CONTEXT__
|
||||
#define __GDK_X11_GL_CONTEXT__
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/glx.h>
|
||||
|
||||
#include "gdkglcontextprivate.h"
|
||||
#include "gdkglpixelformatprivate.h"
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkglpixelformat.h"
|
||||
#include "gdkvisual.h"
|
||||
#include "gdkwindow.h"
|
||||
#include "gdkinternals.h"
|
||||
#include "gdkmain.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct _GdkX11GLContext
|
||||
{
|
||||
GdkGLContext parent_instance;
|
||||
|
||||
GLXContext glx_context;
|
||||
GLXFBConfig glx_config;
|
||||
|
||||
GLXDrawable current_drawable;
|
||||
|
||||
Window dummy_drawable;
|
||||
GLXWindow dummy_glx_drawable;
|
||||
|
||||
guint is_direct : 1;
|
||||
};
|
||||
|
||||
struct _GdkX11GLContextClass
|
||||
{
|
||||
GdkGLContextClass parent_class;
|
||||
};
|
||||
|
||||
gboolean gdk_x11_display_init_gl (GdkDisplay *display);
|
||||
gboolean gdk_x11_display_validate_gl_pixel_format (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLPixelFormat **validated_format,
|
||||
GError **error);
|
||||
GdkGLContext * gdk_x11_display_create_gl_context (GdkDisplay *display,
|
||||
GdkGLPixelFormat *format,
|
||||
GdkGLContext *share,
|
||||
GError **error);
|
||||
void gdk_x11_display_destroy_gl_context (GdkDisplay *display,
|
||||
GdkGLContext *context);
|
||||
gboolean gdk_x11_display_make_gl_context_current (GdkDisplay *display,
|
||||
GdkGLContext *context,
|
||||
GdkWindow *window);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_X11_GL_CONTEXT__ */
|
@@ -43,6 +43,7 @@
|
||||
#include <gdk/x11/gdkx11display.h>
|
||||
#include <gdk/x11/gdkx11displaymanager.h>
|
||||
#include <gdk/x11/gdkx11dnd.h>
|
||||
#include <gdk/x11/gdkx11glcontext.h>
|
||||
#include <gdk/x11/gdkx11keys.h>
|
||||
#include <gdk/x11/gdkx11property.h>
|
||||
#include <gdk/x11/gdkx11screen.h>
|
||||
|
49
gdk/x11/gdkx11glcontext.h
Normal file
49
gdk/x11/gdkx11glcontext.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglcontext-x11.c: X11 specific OpenGL wrappers
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_X11_GL_CONTEXT_H__
|
||||
#define __GDK_X11_GL_CONTEXT_H__
|
||||
|
||||
#if !defined (__GDKX_H_INSIDE__) && !defined (GDK_COMPILATION)
|
||||
#error "Only <gdk/gdkx.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_X11_TYPE_GL_CONTEXT (gdk_x11_gl_context_get_type ())
|
||||
#define GDK_X11_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_X11_TYPE_GL_CONTEXT, GdkX11GLContext))
|
||||
#define GDK_X11_IS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_X11_TYPE_GL_CONTEXT))
|
||||
|
||||
typedef struct _GdkX11GLContext GdkX11GLContext;
|
||||
typedef struct _GdkX11GLContextClass GdkX11GLContextClass;
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GType gdk_x11_gl_context_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gboolean gdk_x11_display_get_glx_version (GdkDisplay *display,
|
||||
int *major,
|
||||
int *minor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_X11_GL_CONTEXT_H__ */
|
@@ -365,6 +365,7 @@ gtk_public_h_sources = \
|
||||
gtkgesturesingle.h \
|
||||
gtkgestureswipe.h \
|
||||
gtkgesturezoom.h \
|
||||
gtkglarea.h \
|
||||
gtkgrid.h \
|
||||
gtkheaderbar.h \
|
||||
gtkicontheme.h \
|
||||
@@ -937,6 +938,7 @@ gtk_base_c_sources = \
|
||||
gtkgesturesingle.c \
|
||||
gtkgestureswipe.c \
|
||||
gtkgesturezoom.c \
|
||||
gtkglarea.c \
|
||||
gtkgrid.c \
|
||||
gtkheaderbar.c \
|
||||
gtkhsla.c \
|
||||
|
@@ -114,6 +114,7 @@
|
||||
#include <gtk/gtkgesturesingle.h>
|
||||
#include <gtk/gtkgestureswipe.h>
|
||||
#include <gtk/gtkgesturezoom.h>
|
||||
#include <gtk/gtkglarea.h>
|
||||
#include <gtk/gtkgrid.h>
|
||||
#include <gtk/gtkheaderbar.h>
|
||||
#include <gtk/gtkicontheme.h>
|
||||
|
667
gtk/gtkglarea.c
Normal file
667
gtk/gtkglarea.c
Normal file
@@ -0,0 +1,667 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
*
|
||||
* gtkglarea.c: A GL drawing area
|
||||
*
|
||||
* Copyright © 2014 Emmanuele Bassi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "gtkglarea.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkstylecontext.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkglarea
|
||||
* @Title: GtkGLArea
|
||||
* @Short_description: A widget for custom drawing with OpenGL
|
||||
*
|
||||
* #GtkGLArea is a widget that allows drawing with OpenGL.
|
||||
*
|
||||
* #GtkGLArea can set up its own #GdkGLContext using a provided
|
||||
* #GdkGLPixelFormat, or can use a given #GdkGLContext.
|
||||
*
|
||||
* In order to draw, you have to connect to the #GtkGLArea::render signal,
|
||||
* or subclass #GtkGLArea and override the @GtkGLAreaClass.render() virtual
|
||||
* function.
|
||||
*
|
||||
* The #GtkGLArea widget ensures that the #GdkGLContext is associated with
|
||||
* the widget's drawing area, and it is kept updated when the size and
|
||||
* position of the drawing area changes.
|
||||
*
|
||||
* ## Drawing with GtkGLArea ##
|
||||
*
|
||||
* The simplest way to draw using OpenGL commands in a #GtkGLArea is to
|
||||
* create a widget instance and connect to the #GtkGLArea::render signal:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* // create a double buffered pixel format
|
||||
* GdkGLPixelFormat *format =
|
||||
* gdk_gl_pixel_format_new ("double-buffer", TRUE);
|
||||
*
|
||||
* // create a GtkGLArea instance
|
||||
* GtkWidget *gl_area = gtk_gl_area_new (format);
|
||||
*
|
||||
* // the GtkGLArea now owns the GdkGLPixelFormat
|
||||
* g_object_unref (format);
|
||||
*
|
||||
* // connect to the "render" signal
|
||||
* g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
|
||||
* ]|
|
||||
*
|
||||
* The `render()` function will be called when the #GtkGLArea is ready
|
||||
* for you to draw its content:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* static gboolean
|
||||
* render (GtkGLArea *area, GdkGLContext *context)
|
||||
* {
|
||||
* // inside this function it's safe to use GL; the given
|
||||
* // #GdkGLContext has been made current to the drawable
|
||||
* // surface used by the #GtkGLArea and the viewport has
|
||||
* // already been set to be the size of the allocation
|
||||
*
|
||||
* // we can start by clearing the buffer
|
||||
* glClearColor (0, 0, 0, 0);
|
||||
* glClear (GL_COLOR_BUFFER_BIT);
|
||||
*
|
||||
* // draw your object
|
||||
* draw_an_object ();
|
||||
*
|
||||
* // we completed our drawing; the draw commands will be
|
||||
* // flushed at the end of the signal emission chain, and
|
||||
* // the buffers swapped if needed
|
||||
* return TRUE;
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* The `draw_an_object()` function draws a 2D, gold-colored
|
||||
* triangle:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* static void
|
||||
* draw_an_object (void)
|
||||
* {
|
||||
* // set the color
|
||||
* glColor3f (1.0f, 0.85f, 0.35f);
|
||||
*
|
||||
* // draw our triangle
|
||||
* glBegin (GL_TRIANGLES);
|
||||
* {
|
||||
* glVertex3f ( 0.0f, 0.6f, 0.0f);
|
||||
* glVertex3f (-0.2f, -0.3f, 0.0f);
|
||||
* glVertex3f ( 0.2f, -0.3f, 0.0f);
|
||||
* }
|
||||
* glEnd ();
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* This is an extremely simple example; in a real-world application you
|
||||
* would probably replace the immediate mode drawing with persistent
|
||||
* geometry primitives, like a Vertex Buffer Object, and only redraw what
|
||||
* changed in your scene.
|
||||
*
|
||||
* ## Using different OpenGL contexts with GtkGLArea ##
|
||||
*
|
||||
* The #GtkGLArea widget will create a #GdkGLContext for the given
|
||||
* pixel format passed on creation. It is possible, however, to change
|
||||
* this default behavior by connecting to the #GtkGLArea::create-context
|
||||
* signal, or by overriding the #GtkGLAreaClass.create_context() virtual
|
||||
* function on a #GtkGLArea subclass.
|
||||
*
|
||||
* If you need to let a #GtkGLArea create a #GdkGLContext with shared
|
||||
* data with another context you can use the #GtkGLArea::create-context
|
||||
* to override the creation of the widget-specific OpenGL context:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* static GdkGLContext *
|
||||
* create_shared_context (GtkGLArea *area,
|
||||
* GdkGLPixelFormat *format,
|
||||
* GdkGLContext *shared_context)
|
||||
* {
|
||||
* GdkDisplay *display;
|
||||
*
|
||||
* display = gtk_widget_get_display (GTK_WIDGET (area));
|
||||
* if (display == NULL)
|
||||
* display = gdk_display_get_default ();
|
||||
*
|
||||
* // create a GdkGLContext that has shared texture namespace
|
||||
* // and display lists with a given context
|
||||
* return gdk_display_create_shared_gl_context (display, format,
|
||||
* shared_context,
|
||||
* NULL);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* The #GtkGLArea will take ownership of the #GdkGLContext returned
|
||||
* by the #GtkGLArea::create-context signal.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
GdkGLPixelFormat *pixel_format;
|
||||
GdkGLContext *context;
|
||||
} GtkGLAreaPrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_PIXEL_FORMAT,
|
||||
PROP_CONTEXT,
|
||||
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[LAST_PROP] = { NULL, };
|
||||
|
||||
enum {
|
||||
RENDER,
|
||||
CREATE_CONTEXT,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint area_signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkGLArea, gtk_gl_area, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
gtk_gl_area_dispose (GObject *gobject)
|
||||
{
|
||||
GtkGLArea *self = GTK_GL_AREA (gobject);
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (self);
|
||||
|
||||
g_clear_object (&priv->pixel_format);
|
||||
g_clear_object (&priv->context);
|
||||
|
||||
G_OBJECT_CLASS (gtk_gl_area_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkGLArea *self = GTK_GL_AREA (gobject);
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PIXEL_FORMAT:
|
||||
priv->pixel_format = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (GTK_GL_AREA (gobject));
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PIXEL_FORMAT:
|
||||
g_value_set_object (value, priv->pixel_format);
|
||||
break;
|
||||
|
||||
case PROP_CONTEXT:
|
||||
g_value_set_object (value, priv->context);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static GdkGLContext *
|
||||
gtk_gl_area_create_context (GtkGLArea *area)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (area);
|
||||
GdkGLContext *context;
|
||||
|
||||
if (priv->context != NULL)
|
||||
return priv->context;
|
||||
|
||||
context = NULL;
|
||||
g_signal_emit (area, area_signals[CREATE_CONTEXT], 0,
|
||||
priv->pixel_format,
|
||||
&context);
|
||||
|
||||
if (context == NULL)
|
||||
{
|
||||
g_critical ("No GL context was created for the widget");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_widget_set_visual (GTK_WIDGET (area), gdk_gl_context_get_visual (context));
|
||||
|
||||
priv->context = context;
|
||||
|
||||
return priv->context;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_realize (GtkWidget *widget)
|
||||
{
|
||||
GdkGLContext *context;
|
||||
GtkAllocation allocation;
|
||||
GdkWindow *window;
|
||||
GdkWindowAttr attributes;
|
||||
gint attributes_mask;
|
||||
|
||||
context = gtk_gl_area_create_context (GTK_GL_AREA (widget));
|
||||
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
attributes.window_type = GDK_WINDOW_CHILD;
|
||||
attributes.x = allocation.x;
|
||||
attributes.y = allocation.y;
|
||||
attributes.width = allocation.width;
|
||||
attributes.height = allocation.height;
|
||||
attributes.wclass = GDK_INPUT_OUTPUT;
|
||||
attributes.visual = gtk_widget_get_visual (widget);
|
||||
attributes.event_mask = gtk_widget_get_events (widget) |
|
||||
GDK_EXPOSURE_MASK |
|
||||
GDK_STRUCTURE_MASK;
|
||||
|
||||
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
|
||||
|
||||
window = gdk_window_new (gtk_widget_get_parent_window (widget),
|
||||
&attributes,
|
||||
attributes_mask);
|
||||
gtk_widget_register_window (widget, window);
|
||||
gtk_widget_set_window (widget, window);
|
||||
|
||||
if (context != NULL)
|
||||
{
|
||||
gdk_gl_context_set_window (context, window);
|
||||
gdk_gl_context_update (context);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_unrealize (GtkWidget *widget)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private ((GtkGLArea *) widget);
|
||||
|
||||
if (priv->context != NULL)
|
||||
gdk_gl_context_set_window (priv->context, NULL);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_gl_area_parent_class)->unrealize (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private ((GtkGLArea *) widget);
|
||||
|
||||
gtk_widget_set_allocation (widget, allocation);
|
||||
|
||||
if (!gtk_widget_get_realized (widget))
|
||||
return;
|
||||
|
||||
gdk_window_move_resize (gtk_widget_get_window (widget),
|
||||
allocation->x,
|
||||
allocation->y,
|
||||
allocation->width,
|
||||
allocation->height);
|
||||
|
||||
if (priv->context != NULL)
|
||||
gdk_gl_context_update (priv->context);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_gl_area_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GtkGLArea *self = GTK_GL_AREA (widget);
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (self);
|
||||
gboolean unused;
|
||||
|
||||
if (priv->context == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!gtk_gl_area_make_current (self))
|
||||
return FALSE;
|
||||
|
||||
g_signal_emit (self, area_signals[RENDER], 0, priv->context, &unused);
|
||||
|
||||
/* XXX: this will go away once gdk_window_end_paint() knows about
|
||||
* GdkGLContext and calls it implicitly when needed
|
||||
*/
|
||||
gtk_gl_area_flush_buffer (self);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_screen_changed (GtkWidget *widget,
|
||||
GdkScreen *old_screen)
|
||||
{
|
||||
GtkGLArea *self = GTK_GL_AREA (widget);
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (self);
|
||||
|
||||
/* this will cause the context to be recreated on realize */
|
||||
g_clear_object (&priv->context);
|
||||
}
|
||||
|
||||
static GdkGLContext *
|
||||
gtk_gl_area_real_create_context (GtkGLArea *area,
|
||||
GdkGLPixelFormat *format)
|
||||
{
|
||||
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (area));
|
||||
GdkGLContext *retval;
|
||||
GError *error = NULL;
|
||||
|
||||
if (display == NULL)
|
||||
display = gdk_display_get_default ();
|
||||
|
||||
retval = gdk_display_create_gl_context (display, format, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_critical ("Unable to create a GdkGLContext: %s", error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_context_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer data)
|
||||
{
|
||||
g_value_copy (handler_return, return_accu);
|
||||
|
||||
/* stop after the first handler returning a valid object */
|
||||
return g_value_get_object (handler_return) == NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_class_init (GtkGLAreaClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
klass->create_context = gtk_gl_area_real_create_context;
|
||||
|
||||
widget_class->screen_changed = gtk_gl_area_screen_changed;
|
||||
widget_class->realize = gtk_gl_area_realize;
|
||||
widget_class->unrealize = gtk_gl_area_unrealize;
|
||||
widget_class->size_allocate = gtk_gl_area_size_allocate;
|
||||
widget_class->draw = gtk_gl_area_draw;
|
||||
|
||||
gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_DRAWING_AREA);
|
||||
|
||||
/**
|
||||
* GtkGLArea:pixel-format:
|
||||
*
|
||||
* The #GdkGLPixelFormat used for creating the #GdkGLContext
|
||||
* to be used by the #GtkGLArea widget.
|
||||
*
|
||||
* If you want to query the effective pixel format used by
|
||||
* the #GdkGLContext, you should get the #GtkGLArea:context and
|
||||
* call gdk_gl_context_get_pixel_format().
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_PIXEL_FORMAT] =
|
||||
g_param_spec_object ("pixel-format",
|
||||
P_("Pixel Format"),
|
||||
P_("The GDK pixel format for creating the GL context"),
|
||||
GDK_TYPE_GL_PIXEL_FORMAT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkGLArea:context:
|
||||
*
|
||||
* The #GdkGLContext used by the #GtkGLArea widget.
|
||||
*
|
||||
* The #GtkGLArea widget is responsible for creating the #GdkGLContext
|
||||
* instance. See the #GtkGLArea::create-context signal on how to
|
||||
* override the default behavior.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
obj_props[PROP_CONTEXT] =
|
||||
g_param_spec_object ("context",
|
||||
P_("Context"),
|
||||
P_("The GL context"),
|
||||
GDK_TYPE_GL_CONTEXT,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
gobject_class->set_property = gtk_gl_area_set_property;
|
||||
gobject_class->get_property = gtk_gl_area_get_property;
|
||||
gobject_class->dispose = gtk_gl_area_dispose;
|
||||
|
||||
g_object_class_install_properties (gobject_class, LAST_PROP, obj_props);
|
||||
|
||||
/**
|
||||
* GtkGLArea::create-context:
|
||||
* @area: the #GtkGLArea that emitted the signal
|
||||
* @format: the #GdkGLPixelFormat for the OpenGL context
|
||||
*
|
||||
* The ::create-context signal is emitted each time a #GtkGLArea needs
|
||||
* to create a #GdkGLContext for the given pixel format.
|
||||
*
|
||||
* Widgets can change #GdkDisplay, #GdkScreen, or #GdkVisual; this
|
||||
* implies that a valid pixel format for a specific #GdkDisplay may
|
||||
* not be valid any more after a change in those objects.
|
||||
*
|
||||
* The #GtkGLArea widget will presently emit the ::create-context
|
||||
* signal when:
|
||||
*
|
||||
* - the #GtkWidget::screen-changed signal is emitted
|
||||
* - the #GtkWidget::realize signal is emitted
|
||||
*
|
||||
* Returns: (transfer full): a newly created #GdkGLContext; the
|
||||
* #GtkGLArea widget will take ownership of the returned value.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
area_signals[CREATE_CONTEXT] =
|
||||
g_signal_new (I_("create-context"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkGLAreaClass, create_context),
|
||||
create_context_accumulator, NULL,
|
||||
_gtk_marshal_OBJECT__OBJECT,
|
||||
GDK_TYPE_GL_CONTEXT, 1,
|
||||
GDK_TYPE_GL_PIXEL_FORMAT);
|
||||
|
||||
/**
|
||||
* GtkGLArea::render:
|
||||
* @area: the #GtkGLArea that emitted the signal
|
||||
* @context: the #GdkGLContext used by @area
|
||||
*
|
||||
* The ::render signal is emitted every time the contents
|
||||
* of the #GtkGLArea should be redrawn.
|
||||
*
|
||||
* The @context is bound to the @area prior to emitting this function,
|
||||
* and the buffers are flushed once the emission terminates.
|
||||
*
|
||||
* Returns: %TRUE to stop other handlers from being invoked for the event.
|
||||
* %FALSE to propagate the event further.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
area_signals[RENDER] =
|
||||
g_signal_new (I_("render"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkGLAreaClass, render),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
NULL,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
GDK_TYPE_GL_CONTEXT);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gl_area_init (GtkGLArea *self)
|
||||
{
|
||||
gtk_widget_set_has_window (GTK_WIDGET (self), TRUE);
|
||||
gtk_widget_set_app_paintable (GTK_WIDGET (self), TRUE);
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
/* FIXME: we need this because double buffering inside GDK will
|
||||
* clear the GL drawable we use, which means flickering. the
|
||||
* proper way to fix this is to make GDK understand that a GDK
|
||||
* window backed by a native window with a GL context will draw
|
||||
* on the window itself, and that all the other drawing should
|
||||
* happen on a seperate surface, which will then get blended via
|
||||
* GL.
|
||||
*/
|
||||
gtk_widget_set_double_buffered (GTK_WIDGET (self), FALSE);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_gl_area_new:
|
||||
* @pixel_format: a #GdkGLPixelFormat
|
||||
*
|
||||
* Creates a new #GtkGLArea widget using the given @pixel_format to
|
||||
* configure a #GdkGLContext.
|
||||
*
|
||||
* Returns: (transfer full): the newly created #GtkGLArea
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_gl_area_new (GdkGLPixelFormat *pixel_format)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (pixel_format), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_GL_AREA,
|
||||
"pixel-format", pixel_format,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_gl_area_get_pixel_format:
|
||||
* @area: a #GtkGLArea
|
||||
*
|
||||
* Retrieves the #GdkGLPixelFormat used by @area.
|
||||
*
|
||||
* Returns: (transfer none): the #GdkGLPixelFormat
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkGLPixelFormat *
|
||||
gtk_gl_area_get_pixel_format (GtkGLArea *area)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (area);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_GL_AREA (area), NULL);
|
||||
|
||||
return priv->pixel_format;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_gl_area_get_context:
|
||||
* @area: a #GtkGLArea
|
||||
*
|
||||
* Retrieves the #GdkGLContext used by @area.
|
||||
*
|
||||
* Returns: (transfer none): the #GdkGLContext
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
GdkGLContext *
|
||||
gtk_gl_area_get_context (GtkGLArea *area)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (area);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_GL_AREA (area), NULL);
|
||||
|
||||
return priv->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_gl_area_make_current:
|
||||
* @area: a #GtkGLArea
|
||||
*
|
||||
* Ensures that the #GdkGLContext used by @area is associated with
|
||||
* the #GtkGLArea.
|
||||
*
|
||||
* This function is automatically called before emitting the
|
||||
* #GtkGLArea::render signal, and should not be called by
|
||||
* application code.
|
||||
*
|
||||
* Returns: %TRUE if the context was associated successfully with
|
||||
* the widget
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
gboolean
|
||||
gtk_gl_area_make_current (GtkGLArea *area)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (area);
|
||||
GtkWidget *widget;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_GL_AREA (area), FALSE);
|
||||
|
||||
widget = GTK_WIDGET (area);
|
||||
g_return_val_if_fail (gtk_widget_get_realized (widget), FALSE);
|
||||
|
||||
if (priv->context == NULL)
|
||||
return FALSE;
|
||||
|
||||
gdk_gl_context_set_window (priv->context, gtk_widget_get_window (widget));
|
||||
|
||||
return gdk_gl_context_make_current (priv->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_gl_area_flush_buffer:
|
||||
* @area: a #GtkGLArea
|
||||
*
|
||||
* Flushes the buffer associated with @area.
|
||||
*
|
||||
* This function is automatically called after emitting
|
||||
* the #GtkGLArea::render signal, and should not be called
|
||||
* by application code.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
void
|
||||
gtk_gl_area_flush_buffer (GtkGLArea *area)
|
||||
{
|
||||
GtkGLAreaPrivate *priv = gtk_gl_area_get_instance_private (area);
|
||||
|
||||
g_return_if_fail (GTK_IS_GL_AREA (area));
|
||||
g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (area)));
|
||||
|
||||
if (priv->context == NULL)
|
||||
return;
|
||||
|
||||
gdk_gl_context_flush_buffer (priv->context);
|
||||
}
|
96
gtk/gtkglarea.h
Normal file
96
gtk/gtkglarea.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
*
|
||||
* gtkglarea.h: A GL drawing area
|
||||
*
|
||||
* Copyright © 2014 Emmanuele Bassi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_GL_AREA_H__
|
||||
#define __GTK_GL_AREA_H__
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_GL_AREA (gtk_gl_area_get_type ())
|
||||
#define GTK_GL_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_GL_AREA, GtkGLArea))
|
||||
#define GTK_IS_GL_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_GL_AREA))
|
||||
#define GTK_GL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_GL_AREA, GtkGLAreaClass))
|
||||
#define GTK_IS_GL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_GL_AREA))
|
||||
#define GTK_GL_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GL_AREA, GtkGLAreaClass))
|
||||
|
||||
typedef struct _GtkGLArea GtkGLArea;
|
||||
typedef struct _GtkGLAreaClass GtkGLAreaClass;
|
||||
|
||||
/**
|
||||
* GtkGLArea:
|
||||
*
|
||||
* A #GtkWidget used for drawing with OpenGL.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
struct _GtkGLArea
|
||||
{
|
||||
/*< private >*/
|
||||
GtkWidget parent_instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* GtkGLAreaClass:
|
||||
* @create_context: class closure for the #GtkGLArea::create-context signal
|
||||
* @render: class closure for the #GtkGLArea::render signal
|
||||
*
|
||||
* The `GtkGLAreaClass` structure contains only private data.
|
||||
*
|
||||
* Since: 3.14
|
||||
*/
|
||||
struct _GtkGLAreaClass
|
||||
{
|
||||
/*< private >*/
|
||||
GtkWidgetClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
GdkGLContext * (* create_context) (GtkGLArea *area,
|
||||
GdkGLPixelFormat *format);
|
||||
|
||||
gboolean (* render) (GtkGLArea *area,
|
||||
GdkGLContext *context);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _padding[6];
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GType gtk_gl_area_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GtkWidget * gtk_gl_area_new (GdkGLPixelFormat *format);
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
GdkGLContext * gtk_gl_area_get_context (GtkGLArea *area);
|
||||
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
gboolean gtk_gl_area_make_current (GtkGLArea *area);
|
||||
GDK_AVAILABLE_IN_3_14
|
||||
void gtk_gl_area_flush_buffer (GtkGLArea *area);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_GL_AREA_H__ */
|
@@ -124,6 +124,7 @@ VOID:UINT,STRING,UINT
|
||||
VOID:UINT,UINT
|
||||
VOID:VOID
|
||||
OBJECT:OBJECT,INT,INT
|
||||
OBJECT:OBJECT
|
||||
VOID:POINTER,POINTER,POINTER,POINTER,STRING
|
||||
VOID:OBJECT,STRING,POINTER,POINTER
|
||||
INT:INT
|
||||
|
@@ -66,6 +66,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
|
||||
testfullscreen \
|
||||
testgeometry \
|
||||
testgiconpixbuf \
|
||||
testglarea \
|
||||
testgrid \
|
||||
testgtk \
|
||||
testheaderbar \
|
||||
|
193
tests/testglarea.c
Normal file
193
tests/testglarea.c
Normal file
@@ -0,0 +1,193 @@
|
||||
#include <stdlib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
enum {
|
||||
X_AXIS,
|
||||
Y_AXIS,
|
||||
Z_AXIS,
|
||||
|
||||
N_AXIS
|
||||
};
|
||||
|
||||
static float rotation_angles[N_AXIS] = { 0.0 };
|
||||
|
||||
static GtkWidget *gl_area;
|
||||
|
||||
static void
|
||||
draw_triangle (void)
|
||||
{
|
||||
glColor3f (1.0f, 0.85f, 0.35f);
|
||||
glBegin (GL_TRIANGLES);
|
||||
{
|
||||
glVertex3f ( 0.0, 0.6, 0.0);
|
||||
glVertex3f (-0.2, -0.3, 0.0);
|
||||
glVertex3f ( 0.2, -0.3, 0.0);
|
||||
}
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
render (GtkGLArea *area,
|
||||
GdkGLContext *context)
|
||||
{
|
||||
glClearColor (0.5, 0.5, 0.5, 1.0);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity ();
|
||||
glRotatef (rotation_angles[X_AXIS], 1, 0, 0);
|
||||
glRotatef (rotation_angles[Y_AXIS], 0, 1, 0);
|
||||
glRotatef (rotation_angles[Z_AXIS], 0, 0, 1);
|
||||
|
||||
draw_triangle ();
|
||||
|
||||
glFlush ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
init (GtkWidget *widget)
|
||||
{
|
||||
GdkGLContext *context = gtk_gl_area_get_context (GTK_GL_AREA (widget));
|
||||
GdkGLPixelFormat *format = gdk_gl_context_get_pixel_format (context);
|
||||
|
||||
g_print ("GL Pixel format:\n"
|
||||
" - double-buffer: %s\n"
|
||||
" - multi-sample: %s\n"
|
||||
" - stereo: %s\n"
|
||||
" - color-size: %d, alpha-size: %d\n"
|
||||
" - depth-size: %d\n"
|
||||
" - stencil-size: %d\n"
|
||||
" - aux-buffers: %d\n"
|
||||
" - accum-size: %d\n"
|
||||
" - sample-buffers: %d\n"
|
||||
" - samples: %d\n\n",
|
||||
gdk_gl_pixel_format_get_double_buffer (format) ? "yes" : "no",
|
||||
gdk_gl_pixel_format_get_multi_sample (format) ? "yes" : "no",
|
||||
gdk_gl_pixel_format_get_stereo (format) ? "yes" : "no",
|
||||
gdk_gl_pixel_format_get_color_size (format),
|
||||
gdk_gl_pixel_format_get_alpha_size (format),
|
||||
gdk_gl_pixel_format_get_depth_size (format),
|
||||
gdk_gl_pixel_format_get_stencil_size (format),
|
||||
gdk_gl_pixel_format_get_aux_buffers (format),
|
||||
gdk_gl_pixel_format_get_accum_size (format),
|
||||
gdk_gl_pixel_format_get_sample_buffers (format),
|
||||
gdk_gl_pixel_format_get_samples (format));
|
||||
}
|
||||
|
||||
static void
|
||||
on_axis_value_change (GtkAdjustment *adjustment,
|
||||
gpointer data)
|
||||
{
|
||||
int axis = GPOINTER_TO_INT (data);
|
||||
|
||||
if (axis < 0 || axis >= N_AXIS)
|
||||
return;
|
||||
|
||||
rotation_angles[axis] = gtk_adjustment_get_value (adjustment);
|
||||
|
||||
gtk_widget_queue_draw (gl_area);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_axis_slider (int axis)
|
||||
{
|
||||
GtkWidget *box, *label, *slider;
|
||||
GtkAdjustment *adj;
|
||||
const char *text;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE);
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case X_AXIS:
|
||||
text = "X axis";
|
||||
break;
|
||||
|
||||
case Y_AXIS:
|
||||
text = "Y axis";
|
||||
break;
|
||||
|
||||
case Z_AXIS:
|
||||
text = "Z axis";
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
label = gtk_label_new (text);
|
||||
gtk_container_add (GTK_CONTAINER (box), label);
|
||||
gtk_widget_show (label);
|
||||
|
||||
adj = gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 12.0, 0.0);
|
||||
g_signal_connect (adj, "value-changed",
|
||||
G_CALLBACK (on_axis_value_change),
|
||||
GINT_TO_POINTER (axis));
|
||||
slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adj);
|
||||
gtk_container_add (GTK_CONTAINER (box), slider);
|
||||
gtk_widget_set_hexpand (slider, TRUE);
|
||||
gtk_widget_show (slider);
|
||||
|
||||
gtk_widget_show (box);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GtkWidget *window, *box, *button, *controls;
|
||||
GdkGLPixelFormat *pixel_format;
|
||||
int i;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
/* create a new pixel format; we use this to configure the
|
||||
* GL context, and to check for features
|
||||
*/
|
||||
pixel_format = gdk_gl_pixel_format_new ("double-buffer", TRUE,
|
||||
NULL);
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "GtkGLArea - Golden Triangle");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 12);
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
||||
gtk_widget_show (window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
|
||||
gtk_box_set_spacing (GTK_BOX (box), 6);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
gtk_widget_show (box);
|
||||
|
||||
gl_area = gtk_gl_area_new (pixel_format);
|
||||
gtk_widget_set_hexpand (gl_area, TRUE);
|
||||
gtk_widget_set_vexpand (gl_area, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), gl_area);
|
||||
g_signal_connect (gl_area, "realize", G_CALLBACK (init), NULL);
|
||||
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
|
||||
gtk_widget_show (gl_area);
|
||||
g_object_unref (pixel_format);
|
||||
|
||||
controls = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
|
||||
gtk_container_add (GTK_CONTAINER (box), controls);
|
||||
gtk_widget_set_hexpand (controls, TRUE);
|
||||
gtk_widget_show (controls);
|
||||
|
||||
for (i = 0; i < N_AXIS; i++)
|
||||
gtk_container_add (GTK_CONTAINER (controls), create_axis_slider (i));
|
||||
|
||||
button = gtk_button_new_with_label ("Quit");
|
||||
gtk_widget_set_hexpand (button, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
|
||||
gtk_widget_show (button);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Reference in New Issue
Block a user