Compare commits

...

20 Commits

Author SHA1 Message Date
Emmanuele Bassi
1b0b2c1e39 demo: Move the GLSL shaders to resources
It's easier to use them or modify them as separate files, instead of
inlined inside the C source.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-09 16:32:57 +00:00
Emmanuele Bassi
8eb58dc557 gl: Clean up the required version accessors
We can simplify the code, since we only have core GL profiles in GDK.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-09 16:10:22 +00:00
Emmanuele Bassi
c3c338dcc0 docs: We do not support non-core GL profiles
No need to mention that some API only works on core GL profiles in the
GdkGLContext docs.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-09 16:09:25 +00:00
Emmanuele Bassi
9f28994f10 gl: Clean up pre-requisite checks for GdkGLContext setters
We don't support non-core profiles.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-09 16:08:43 +00:00
Emmanuele Bassi
c4df6af425 wayland/gl: Ensure we use the 3.2 core profile
Emit an error if the profile is different.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-09 15:56:18 +00:00
Emmanuele Bassi
5043eeaf3e x11/gl: Ensure we use the 3.2 core profile
Drop the dead code for the legacy profile, and return an error when
realizing if the profile is incorrect.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-09 15:55:08 +00:00
Emmanuele Bassi
1102d047b6 demos: Update the GtkGLArea demo code
Same way we updated the testglarea test code.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Emmanuele Bassi
ab7d8c3044 tests: Update testglarea
Since we dropped the legacy OpenGL compatibility profile, we need to use
recent OpenGL APi and concepts. This also means that the example code
gets a tad more complicated.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Emmanuele Bassi
d9ecc88728 gl: Add more debugging notes
https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Emmanuele Bassi
cfdfa1c9be glarea: Do not use extension API
We are using GL contexts with Core GL profiles, so we need to use the
proper API, not the one provided by extensions.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Emmanuele Bassi
3ff6a71923 gl: Do not use the extension API for core GL
Since we are using a Core GL profile, we need to drop the
extension-based API.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Emmanuele Bassi
8846a7002c gl: Drop OpenGL legacy profile
We simply don't want to care about legacy OpenGL.

All supported platforms also have support for OpenGL ≥ 3.2; it would
complicate the internal code; and would force us to use legacy GL
contexts internally if the first context created by the user is a legacy
GL context, and disable creation of core-3.2 contexts after that.

We will need to fix all our code examples to use the Core 3.2 profile.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Emmanuele Bassi
bd26ebde63 gl: Move getters for context options to the public API
They can be useful for third party code as well.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Emmanuele Bassi
4bf387eb37 Switch GDK_GL_PROFILE_DEFAULT to mean 3_2_CORE
Instead of LEGACY.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:47:02 +00:00
Chun-wei Fan
7976c7c80b win32/gl: Use the GdkGLContext options
https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:43:43 +00:00
Chun-wei Fan
26390d0bbc GDK-Win32: Split GL context creation in two phases
Like what is being done in the X11 and Wayland backends, create the
GdkWin32GLContext in 2 steps, where we only create the actual WGL context
in _gdk_win32_gl_context_realize().

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 17:43:43 +00:00
Emmanuele Bassi
52570ed5ff wayland/gl: Use the GdkGLContext options
https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 16:27:47 +00:00
Emmanuele Bassi
e9276c1080 x11/gl: Use the GdkGLContext options
When creating an OpenGL context using the glXCreateContextAttribs()
function.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 16:27:47 +00:00
Emmanuele Bassi
dd4fdea535 gl: Add context options
Users of the GdkGLContext API should be allowed to set properties on the
shim GdkGLContext instance prior to realization, so that the
backend-specific implementation can use the value of those properties
when creating the windowing system specific resources.

The main three options are:

 • a major/minor version tuple, to request a specific GL version
 • a debug bit, to request a "debug context", which provides additional
   validation and run time checking
 • a forward compatibility bit, to request a context that does not
   have deprecated functionality

See also:
 - https://www.opengl.org/registry/specs/ARB/glx_create_context.txt

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 16:27:47 +00:00
Emmanuele Bassi
4b08b9f239 GL: Split GL context creation in two phases
One of the major requests by OpenGL users has been the ability to
specify settings when creating a GL context, like the version to use
or whether the debug support should be enabled.

We have a couple of requirements in terms of API:

 • avoid, if at all possible, the "C arrays of integers with
   attribute, value pairs", which are hard to write and hard
   to bind in non-C languages.
 • allow failing in a recoverable way.
 • do not make the GL context creation API a mess of arguments.

Looking at prior art, it seems that a common pattern is to split the
construction phase in two:

 • a first phase that creates a GL context wrapper object and
   does preliminary checks on the environment.
 • a second phase that creates the backend-specific GL object.

We adopted a similar pattern:

 • gdk_window_create_gl_context() creates a GdkGLContext
 • gdk_gl_context_realize() creates the underlying resources

Calling gdk_gl_context_make_current() also realizes the context, so
simple GL users do not need to care. Advanced users will want to
call gdk_window_create_gl_context(), set up the optional requirements,
and then call gdk_gl_context_realize(). If either of these two steps
fails, it's possible to recover by changing the requirements, or simply
creating a new GdkGLContext instance.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
2015-02-05 16:27:46 +00:00
19 changed files with 1251 additions and 325 deletions

View File

@@ -136,6 +136,8 @@ RESOURCES = \
brick2.png \
background.jpg \
floppybuddy.gif \
glarea-fragment.glsl \
glarea-vertex.glsl \
gnome-applets.png \
gnome-calendar.png \
gnome-foot.png \

View File

@@ -140,4 +140,8 @@
<gresource prefix="/popover">
<file>popover.ui</file>
</gresource>
<gresource prefix="/shaders">
<file>glarea-fragment.glsl</file>
<file>glarea-vertex.glsl</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,9 @@
#version 330
out vec4 outputColor;
void main() {
float lerpVal = gl_FragCoord.y / 500.0f;
outputColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpVal);
}

View File

@@ -0,0 +1,8 @@
#version 330
layout(location = 0) in vec4 position;
uniform mat4 mvp;
void main() {
gl_Position = mvp * position;
}

View File

@@ -3,6 +3,7 @@
* GtkGLArea is a widget that allows custom drawing using OpenGL calls.
*/
#include <math.h>
#include <gtk/gtk.h>
#include <epoxy/gl.h>
@@ -23,35 +24,261 @@ enum {
static float rotation_angles[N_AXIS] = { 0.0 };
/* The object we are drawing */
static const GLfloat vertex_data[] = {
0.f, 0.5f, 0.f, 1.f,
0.5f, -0.366f, 0.f, 1.f,
-0.5f, -0.366f, 0.f, 1.f,
};
/* Initialize the GL buffers */
static void
init_buffers (GLuint *vao_out,
GLuint *buffer_out)
{
GLuint vao, buffer;
/* We only use one VAO, so we always keep it bound */
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
/* This is the buffer that holds the vertices */
glGenBuffers (1, &buffer);
glBindBuffer (GL_ARRAY_BUFFER, buffer);
glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data, GL_STATIC_DRAW);
glBindBuffer (GL_ARRAY_BUFFER, 0);
if (vao_out != NULL)
*vao_out = vao;
if (buffer_out != NULL)
*buffer_out = buffer;
}
/* Create and compile a shader */
static GLuint
create_shader (int type,
const char *src)
{
GLuint shader;
int status;
shader = glCreateShader (type);
glShaderSource (shader, 1, &src, NULL);
glCompileShader (shader);
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
int log_len;
char *buffer;
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc (log_len + 1);
glGetShaderInfoLog (shader, log_len, NULL, buffer);
g_warning ("Compile failure in %s shader:\n%s\n",
type == GL_VERTEX_SHADER ? "vertex" : "fragment",
buffer);
g_free (buffer);
glDeleteShader (shader);
return 0;
}
return shader;
}
/* Initialize the shaders and link them into a program */
static void
init_shaders (GLuint *program_out,
GLuint *mvp_out)
{
GLuint vertex, fragment;
GLuint program = 0;
GLuint mvp = 0;
int status;
GBytes *source;
source = g_resources_lookup_data ("/shaders/glarea-vertex.glsl", 0, NULL);
vertex = create_shader (GL_VERTEX_SHADER, g_bytes_get_data (source, NULL));
g_bytes_unref (source);
if (vertex == 0)
{
*program_out = 0;
return;
}
source = g_resources_lookup_data ("/shaders/glarea-fragment.glsl", 0, NULL);
fragment = create_shader (GL_FRAGMENT_SHADER, g_bytes_get_data (source, NULL));
g_bytes_unref (source);
if (fragment == 0)
{
glDeleteShader (vertex);
*program_out = 0;
return;
}
program = glCreateProgram ();
glAttachShader (program, vertex);
glAttachShader (program, fragment);
glLinkProgram (program);
glGetProgramiv (program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
int log_len;
char *buffer;
glGetProgramiv (program, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc (log_len + 1);
glGetProgramInfoLog (program, log_len, NULL, buffer);
g_warning ("Linking failure:\n%s\n", buffer);
g_free (buffer);
glDeleteProgram (program);
program = 0;
goto out;
}
/* Get the location of the "mvp" uniform */
mvp = glGetUniformLocation (program, "mvp");
glDetachShader (program, vertex);
glDetachShader (program, fragment);
out:
glDeleteShader (vertex);
glDeleteShader (fragment);
if (program_out != NULL)
*program_out = program;
if (mvp_out != NULL)
*mvp_out = mvp;
}
static void
compute_mvp (float *res,
float phi,
float theta,
float psi)
{
float x = phi * (G_PI / 180.f);
float y = theta * (G_PI / 180.f);
float z = psi * (G_PI / 180.f);
float c1 = cosf (x), s1 = sinf (x);
float c2 = cosf (y), s2 = sinf (y);
float c3 = cosf (z), s3 = sinf (z);
float c3c2 = c3 * c2;
float s3c1 = s3 * c1;
float c3s2s1 = c3 * s2 * s1;
float s3s1 = s3 * s1;
float c3s2c1 = c3 * s2 * c1;
float s3c2 = s3 * c2;
float c3c1 = c3 * c1;
float s3s2s1 = s3 * s2 * s1;
float c3s1 = c3 * s1;
float s3s2c1 = s3 * s2 * c1;
float c2s1 = c2 * s1;
float c2c1 = c2 * c1;
/* initialize to the identity matrix */
res[0] = 1.f; res[4] = 0.f; res[8] = 0.f; res[12] = 0.f;
res[1] = 0.f; res[5] = 1.f; res[9] = 0.f; res[13] = 0.f;
res[2] = 0.f; res[6] = 0.f; res[10] = 1.f; res[14] = 0.f;
res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f;
/* apply all three rotations using the three matrices:
*
* ⎡ c3 s3 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ 1 0 0 ⎤
* ⎢ -s3 c3 0 ⎥ ⎢ 0 1 0 ⎥ ⎢ 0 c1 s1 ⎥
* ⎣ 0 0 1 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 -s1 c1 ⎦
*/
res[0] = c3c2; res[4] = s3c1 + c3s2s1; res[8] = s3s1 - c3s2c1; res[12] = 0.f;
res[1] = -s3c2; res[5] = c3c1 - s3s2s1; res[9] = c3s1 + s3s2c1; res[13] = 0.f;
res[2] = s2; res[6] = -c2s1; res[10] = c2c1; res[14] = 0.f;
res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f;
}
static GLuint position_buffer;
static GLuint program;
static GLuint mvp_location;
/* We need to set up our state when we realize the GtkGLArea widget */
static void
realize (GtkWidget *widget)
{
gtk_gl_area_make_current (GTK_GL_AREA (widget));
init_buffers (&position_buffer, NULL);
init_shaders (&program, &mvp_location);
}
/* We should tear down the state when unrealizing */
static void
unrealize (GtkWidget *widget)
{
gtk_gl_area_make_current (GTK_GL_AREA (widget));
glDeleteBuffers (1, &position_buffer);
glDeleteProgram (program);
}
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 ();
float mvp[16];
/* Compute the model view projection matrix using the
* rotation angles specified through the GtkRange widgets
*/
compute_mvp (mvp,
rotation_angles[X_AXIS],
rotation_angles[Y_AXIS],
rotation_angles[Z_AXIS]);
/* Use our shaders */
glUseProgram (program);
/* Update the "mvp" matrix we use in the shader */
glUniformMatrix4fv (mvp_location, 1, GL_FALSE, &mvp[0]);
/* Use the vertices in our buffer */
glBindBuffer (GL_ARRAY_BUFFER, position_buffer);
glEnableVertexAttribArray (0);
glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, 0);
/* Draw the three vertices as a triangle */
glDrawArrays (GL_TRIANGLES, 0, 3);
/* We finished using the buffers and program */
glDisableVertexAttribArray (0);
glBindBuffer (GL_ARRAY_BUFFER, 0);
glUseProgram (0);
}
/* The main rendering callback */
static gboolean
render (GtkGLArea *area,
GdkGLContext *context)
{
/* Clear the viewport */
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 our object */
draw_triangle ();
/* Flush the contents of the pipeline */
glFlush ();
return TRUE;
@@ -138,7 +365,7 @@ create_glarea_window (GtkWidget *do_widget)
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_window_set_default_size (GTK_WINDOW (window), 400, 600);
gtk_container_set_border_width (GTK_CONTAINER (window), 12);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
@@ -151,7 +378,13 @@ create_glarea_window (GtkWidget *do_widget)
gtk_widget_set_vexpand (gl_area, TRUE);
gtk_container_add (GTK_CONTAINER (box), gl_area);
/* the main "draw" call for GtkGLArea */
/* We need to initialize and free GL resources, so we use
* the realize and unrealize signals on the widget
*/
g_signal_connect (gl_area, "realize", G_CALLBACK (realize), NULL);
g_signal_connect (gl_area, "unrealize", G_CALLBACK (unrealize), NULL);
/* The main "draw" call for GtkGLArea */
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
controls = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);

View File

@@ -355,7 +355,7 @@ gdk_cairo_draw_from_gl (cairo_t *cr,
if (source_type == GL_RENDERBUFFER)
{
glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, source);
glBindRenderbuffer (GL_RENDERBUFFER, source);
glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_ALPHA_SIZE, &alpha_size);
}
else if (source_type == GL_TEXTURE)

View File

@@ -49,6 +49,14 @@
* #GdkWindow, which you typically get during the realize call
* of a widget.
*
* A #GdkGLContext is not realized until either gdk_gl_context_make_current(),
* or until it is realized using gdk_gl_context_realize(). It is possible to
* specify details of the GL context like the OpenGL version to be used, or
* whether the GL context should have extra state validation enabled after
* calling gdk_window_create_gl_context() by calling gdk_gl_context_realize().
* If the realization fails you have the option to change the settings of the
* #GdkGLContext and try again.
*
* ## Using a GdkGLContext ##
*
* You will need to make the #GdkGLContext the current context
@@ -85,10 +93,16 @@ typedef struct {
GdkGLContext *shared_context;
GdkGLProfile profile;
int major;
int minor;
guint realized : 1;
guint use_texture_rectangle : 1;
guint has_gl_framebuffer_blit : 1;
guint has_frame_terminator : 1;
guint extensions_checked : 1;
guint debug_enabled : 1;
guint forward_compatible : 1;
GdkGLContextPaintData *paint_data;
} GdkGLContextPrivate;
@@ -389,19 +403,219 @@ gdk_gl_context_has_frame_terminator (GdkGLContext *context)
return priv->has_frame_terminator;
}
/**
* gdk_gl_context_set_debug_enabled:
* @context: a #GdkGLContext
* @enabled: whether to enable debugging in the context
*
* Sets whether the #GdkGLContext should perform extra validations and
* run time checking. This is useful during development, but has
* additional overhead.
*
* The #GdkGLContext must not be realized or made current prior to
* calling this function.
*
* Since: 3.16
*/
void
gdk_gl_context_set_debug_enabled (GdkGLContext *context,
gboolean enabled)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!priv->realized);
enabled = !!enabled;
priv->debug_enabled = enabled;
}
/**
* gdk_gl_context_get_debug_enabled:
* @context: a #GdkGLContext
*
* Retrieves the value set using gdk_gl_context_set_debug_enabled().
*
* Returns: %TRUE if debugging is enabled
*
* Since: 3.16
*/
gboolean
gdk_gl_context_get_debug_enabled (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
return priv->debug_enabled;
}
/**
* gdk_gl_context_set_forward_compatible:
* @context: a #GdkGLContext
* @compatible: whether the context should be forward compatible
*
* Sets whether the #GdkGLContext should be forward compatible.
*
* Forward compatibile contexts must not support OpenGL functionality that
* has been marked as deprecated in the requested version; non-forward
* compatible contexts, on the other hand, must support both deprecated and
* non deprecated functionality.
*
* The #GdkGLContext must not be realized or made current prior to calling
* this function.
*
* Since: 3.16
*/
void
gdk_gl_context_set_forward_compatible (GdkGLContext *context,
gboolean compatible)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!priv->realized);
compatible = !!compatible;
priv->forward_compatible = compatible;
}
/**
* gdk_gl_context_get_forward_compatible:
* @context: a #GdkGLContext
*
* Retrieves the value set using gdk_gl_context_set_forward_compatible().
*
* Returns: %TRUE if the context should be forward compatible
*
* Since: 3.16
*/
gboolean
gdk_gl_context_get_forward_compatible (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
return priv->forward_compatible;
}
/**
* gdk_gl_context_set_required_version:
* @context: a #GdkGLContext
* @major: the major version to request
* @minor: the minor version to request
*
* Sets the major and minor version of OpenGL to request.
*
* Setting @major and @minor to zero will use the default values.
*
* The #GdkGLContext must not be realized or made current prior to calling
* this function.
*
* Since: 3.16
*/
void
gdk_gl_context_set_required_version (GdkGLContext *context,
int major,
int minor)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!priv->realized);
priv->major = MAX (major, 3);
priv->minor = MAX (minor, 2);
}
/**
* gdk_gl_context_get_required_version:
* @context: a #GdkGLContext
* @major: (out) (nullable): return location for the major version to request
* @minor: (out) (nullable): return location for the minor version to request
*
* Retrieves the major and minor version requested by calling
* gdk_gl_context_set_required_version().
*
* Since: 3.16
*/
void
gdk_gl_context_get_required_version (GdkGLContext *context,
int *major,
int *minor)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
int maj, min;
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
if (priv->major > 0)
maj = priv->major;
else
maj = 3;
if (priv->minor > 0)
min = priv->minor;
else
min = 2;
if (major != NULL)
*major = maj;
if (minor != NULL)
*minor = min;
}
/**
* gdk_gl_context_realize:
* @context: a #GdkGLContext
* @error: return location for a #GError
*
* Realizes the given #GdkGLContext.
*
* It is safe to call this function on a realized #GdkGLContext.
*
* Returns: %TRUE if the context is realized
*
* Since: 3.16
*/
gboolean
gdk_gl_context_realize (GdkGLContext *context,
GError **error)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
if (priv->realized)
return TRUE;
priv->realized = GDK_GL_CONTEXT_GET_CLASS (context)->realize (context, error);
return priv->realized;
}
static void
gdk_gl_context_realize (GdkGLContext *context)
gdk_gl_context_check_extensions (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
gboolean has_npot, has_texture_rectangle;
if (!priv->realized)
return;
if (priv->extensions_checked)
return;
has_npot = epoxy_has_gl_extension ("GL_ARB_texture_non_power_of_two");
has_texture_rectangle = epoxy_has_gl_extension ("GL_ARB_texture_rectangle");
priv->has_gl_framebuffer_blit = epoxy_has_gl_extension ("GL_EXT_framebuffer_blit");
priv->has_frame_terminator = epoxy_has_gl_extension ("GL_GREMEDY_frame_terminator");
if (_gdk_gl_flags & GDK_GL_TEXTURE_RECTANGLE)
if (G_UNLIKELY (_gdk_gl_flags & GDK_GL_TEXTURE_RECTANGLE))
priv->use_texture_rectangle = TRUE;
else if (has_npot)
priv->use_texture_rectangle = FALSE;
@@ -410,7 +624,20 @@ gdk_gl_context_realize (GdkGLContext *context)
else
g_warning ("GL implementation doesn't support any form of non-power-of-two textures");
priv->realized = TRUE;
GDK_NOTE (OPENGL,
g_print ("Extensions checked:\n"
" - GL_ARB_texture_non_power_of_two: %s\n"
" - GL_ARB_texture_rectangle: %s\n"
" - GL_EXT_framebuffer_blit: %s\n"
" - GL_GREMEDY_frame_terminator: %s\n"
"Using texture rectangle: %s\n",
has_npot ? "yes" : "no",
has_texture_rectangle ? "yes" : "no",
priv->has_gl_framebuffer_blit ? "yes" : "no",
priv->has_frame_terminator ? "yes" : "no",
priv->use_texture_rectangle ? "yes" : "no"));
priv->extensions_checked = TRUE;
}
/**
@@ -433,11 +660,24 @@ gdk_gl_context_make_current (GdkGLContext *context)
if (current == context)
return;
/* we need to realize the GdkGLContext if it wasn't explicitly realized */
if (!priv->realized)
{
GError *error = NULL;
gdk_gl_context_realize (context, &error);
if (error != NULL)
{
g_critical ("Could not realize the GL context: %s", error->message);
g_error_free (error);
return;
}
}
if (gdk_display_make_gl_context_current (priv->display, context))
{
g_private_replace (&thread_current_context, g_object_ref (context));
if (!priv->realized)
gdk_gl_context_realize (context);
gdk_gl_context_check_extensions (context);
}
}
@@ -496,7 +736,7 @@ gdk_gl_context_get_profile (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), GDK_GL_PROFILE_LEGACY);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), GDK_GL_PROFILE_DEFAULT);
return priv->profile;
}

View File

@@ -43,18 +43,43 @@ GDK_AVAILABLE_IN_3_16
GType gdk_gl_context_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_16
GdkDisplay * gdk_gl_context_get_display (GdkGLContext *context);
GdkDisplay * gdk_gl_context_get_display (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
GdkWindow * gdk_gl_context_get_window (GdkGLContext *context);
GdkWindow * gdk_gl_context_get_window (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
GdkGLProfile gdk_gl_context_get_profile (GdkGLContext *context);
GdkGLProfile gdk_gl_context_get_profile (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
GdkGLContext * gdk_gl_context_get_shared_context (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_make_current (GdkGLContext *context);
void gdk_gl_context_set_required_version (GdkGLContext *context,
int major,
int minor);
GDK_AVAILABLE_IN_3_16
GdkGLContext * gdk_gl_context_get_current (void);
void gdk_gl_context_get_required_version (GdkGLContext *context,
int *major,
int *minor);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_clear_current (void);
void gdk_gl_context_set_debug_enabled (GdkGLContext *context,
gboolean enabled);
GDK_AVAILABLE_IN_3_16
gboolean gdk_gl_context_get_debug_enabled (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_set_forward_compatible (GdkGLContext *context,
gboolean compatible);
GDK_AVAILABLE_IN_3_16
gboolean gdk_gl_context_get_forward_compatible (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
gboolean gdk_gl_context_realize (GdkGLContext *context,
GError **error);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_make_current (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
GdkGLContext * gdk_gl_context_get_current (void);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_clear_current (void);
G_END_DECLS

View File

@@ -40,6 +40,9 @@ struct _GdkGLContextClass
{
GObjectClass parent_class;
gboolean (* realize) (GdkGLContext *context,
GError **error);
void (* end_frame) (GdkGLContext *context,
cairo_region_t *painted,
cairo_region_t *damage);
@@ -71,13 +74,13 @@ typedef struct {
GdkGLContextProgram *current_program;
} GdkGLContextPaintData;
GdkGLContextPaintData *gdk_gl_context_get_paint_data (GdkGLContext *context);
gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context);
gboolean gdk_gl_context_has_framebuffer_blit (GdkGLContext *context);
gboolean gdk_gl_context_has_frame_terminator (GdkGLContext *context);
void gdk_gl_context_end_frame (GdkGLContext *context,
cairo_region_t *painted,
cairo_region_t *damage);
GdkGLContextPaintData * gdk_gl_context_get_paint_data (GdkGLContext *context);
gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context);
gboolean gdk_gl_context_has_framebuffer_blit (GdkGLContext *context);
gboolean gdk_gl_context_has_frame_terminator (GdkGLContext *context);
void gdk_gl_context_end_frame (GdkGLContext *context,
cairo_region_t *painted,
cairo_region_t *damage);
G_END_DECLS

View File

@@ -435,18 +435,28 @@ struct _GdkPoint
/**
* GdkGLProfile:
* @GDK_GL_PROFILE_DEFAULT: ...
* @GDK_GL_PROFILE_LEGACY: ...
* @GDK_GL_PROFILE_3_2_CORE: ...
* @GDK_GL_PROFILE_DEFAULT: The default profile.
* @GDK_GL_PROFILE_3_2_CORE: Use core 3.2 GL profiles
*
* ...
* The profile to be used when creating a #GdkGLContext.
*
* Since: 3.16
*/
typedef enum {
GDK_GL_PROFILE_DEFAULT,
GDK_GL_PROFILE_LEGACY,
GDK_GL_PROFILE_3_2_CORE
} GdkGLProfile;
/**
* GdkGLError:
* @GDK_GL_ERROR_NOT_AVAILABLE: OpenGL support is not available
* @GDK_GL_ERROR_UNSUPPORTED_FORMAT: The requested visual format is not supported
* @GDK_GL_ERROR_UNSUPPORTED_PROFILE: The requested profile is not supported
*
* Error enumeration for #GdkGLContext.
*
* Since: 3.16
*/
typedef enum {
GDK_GL_ERROR_NOT_AVAILABLE,
GDK_GL_ERROR_UNSUPPORTED_FORMAT,

View File

@@ -2724,8 +2724,11 @@ gdk_window_ref_impl_surface (GdkWindow *window)
}
GdkGLContext *
gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
gdk_window_get_paint_gl_context (GdkWindow *window,
GError **error)
{
GError *internal_error = NULL;
if (_gdk_gl_flags & GDK_GL_DISABLE)
{
g_set_error_literal (error, GDK_GL_ERROR,
@@ -2739,21 +2742,24 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
window->impl_window->gl_paint_context =
GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window->impl_window,
TRUE,
GDK_GL_PROFILE_3_2_CORE,
GDK_GL_PROFILE_DEFAULT,
NULL,
error);
if (window->impl_window->gl_paint_context == NULL &&
g_error_matches (*error, GDK_GL_ERROR,
GDK_GL_ERROR_UNSUPPORTED_PROFILE))
{
g_clear_error (error);
window->impl_window->gl_paint_context =
GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window->impl_window,
TRUE,
GDK_GL_PROFILE_DEFAULT,
NULL,
error);
}
&internal_error);
}
if (internal_error != NULL)
{
g_propagate_error (error, internal_error);
g_clear_object (&(window->impl_window->gl_paint_context));
return NULL;
}
gdk_gl_context_realize (window->impl_window->gl_paint_context, &internal_error);
if (internal_error != NULL)
{
g_propagate_error (error, internal_error);
g_clear_object (&(window->impl_window->gl_paint_context));
return NULL;
}
return window->impl_window->gl_paint_context;
@@ -2771,6 +2777,9 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
*
* If the creation of the #GdkGLContext failed, @error will be set.
*
* Before using the returned #GdkGLContext, you will need to
* call gdk_gl_context_make_current().
*
* Returns: (transfer full): the newly created #GdkGLContext, or
* %NULL on error
*

View File

@@ -1116,7 +1116,6 @@ GdkGLContext * gdk_window_create_gl_context (GdkWindow *window,
GdkGLProfile profile,
GError **error);
G_END_DECLS
#endif /* __GDK_WINDOW_H__ */

View File

@@ -296,6 +296,9 @@ struct _GdkWindowImplClass
GdkGLProfile profile,
GdkGLContext *share,
GError **error);
gboolean (* realize_gl_context) (GdkWindow *window,
GdkGLContext *context,
GError **error);
void (*invalidate_for_new_frame)(GdkWindow *window,
cairo_region_t *update_area);
};
@@ -303,7 +306,6 @@ struct _GdkWindowImplClass
/* Interface Functions */
GType gdk_window_impl_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_WINDOW_IMPL_H__ */

View File

@@ -100,6 +100,79 @@ gdk_wayland_window_invalidate_for_new_frame (GdkWindow *window,
}
}
#define N_EGL_ATTRS 16
static gboolean
gdk_wayland_gl_context_realize (GdkGLContext *context,
GError **error)
{
GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkGLContext *share = gdk_gl_context_get_shared_context (context);
GdkGLProfile profile = gdk_gl_context_get_profile (context);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
EGLContext ctx;
EGLint context_attribs[N_EGL_ATTRS];
int major, minor, flags;
gboolean debug_bit, forward_bit;
int i = 0;
if (profile != GDK_GL_PROFILE_3_2_CORE)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_UNSUPPORTED_PROFILE,
_("Unsupported profile for a GL context"));
return FALSE;
}
gdk_gl_context_get_required_version (context, &major, &minor);
debug_bit = gdk_gl_context_get_debug_enabled (context);
forward_bit = gdk_gl_context_get_forward_compatible (context);
flags = 0;
if (debug_bit)
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
if (forward_bit)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
/* We want a core profile */
context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
context_attribs[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
/* Specify the version */
context_attribs[i++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
context_attribs[i++] = major;
context_attribs[i++] = EGL_CONTEXT_MINOR_VERSION_KHR;
context_attribs[i++] = minor;
/* Specify the flags */
context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
context_attribs[i++] = flags;
context_attribs[i++] = EGL_NONE;
g_assert (i < N_EGL_ATTRS);
ctx = eglCreateContext (display_wayland->egl_display,
context_wayland->egl_config,
share != NULL ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context
: EGL_NO_CONTEXT,
context_attribs);
if (ctx == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return FALSE;
}
GDK_NOTE (OPENGL, g_print ("Created EGL context[%p]\n", ctx));
context_wayland->egl_context = ctx;
return TRUE;
}
static void
gdk_wayland_gl_context_end_frame (GdkGLContext *context,
cairo_region_t *painted,
@@ -142,11 +215,13 @@ gdk_wayland_gl_context_end_frame (GdkGLContext *context,
static void
gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
{
GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
context_class->end_frame = gdk_wayland_gl_context_end_frame;
gobject_class->dispose = gdk_x11_gl_context_dispose;
context_class->realize = gdk_wayland_gl_context_realize;
context_class->end_frame = gdk_wayland_gl_context_end_frame;
}
static void
@@ -213,9 +288,9 @@ gdk_wayland_display_init_gl (GdkDisplay *display)
#define MAX_EGL_ATTRS 30
static gboolean
find_eglconfig_for_window (GdkWindow *window,
EGLConfig *egl_config_out,
GError **error)
find_eglconfig_for_window (GdkWindow *window,
EGLConfig *egl_config_out,
GError **error)
{
GdkDisplay *display = gdk_window_get_display (window);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
@@ -294,10 +369,7 @@ gdk_wayland_window_create_gl_context (GdkWindow *window,
GdkDisplay *display = gdk_window_get_display (window);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkWaylandGLContext *context;
EGLContext ctx;
EGLConfig config;
int i;
EGLint context_attribs[3];
if (!gdk_wayland_display_init_gl (display))
{
@@ -308,7 +380,7 @@ gdk_wayland_window_create_gl_context (GdkWindow *window,
}
if (profile == GDK_GL_PROFILE_DEFAULT)
profile = GDK_GL_PROFILE_LEGACY;
profile = GDK_GL_PROFILE_3_2_CORE;
if (profile == GDK_GL_PROFILE_3_2_CORE &&
!display_wayland->have_egl_khr_create_context)
@@ -322,29 +394,6 @@ gdk_wayland_window_create_gl_context (GdkWindow *window,
if (!find_eglconfig_for_window (window, &config, error))
return NULL;
i = 0;
if (profile == GDK_GL_PROFILE_3_2_CORE)
{
context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
context_attribs[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
}
context_attribs[i++] = EGL_NONE;
ctx = eglCreateContext (display_wayland->egl_display,
config,
share ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context : EGL_NO_CONTEXT,
context_attribs);
if (ctx == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return NULL;
}
GDK_NOTE (OPENGL,
g_print ("Created EGL context[%p]\n", ctx));
context = g_object_new (GDK_TYPE_WAYLAND_GL_CONTEXT,
"display", display,
"window", window,
@@ -353,7 +402,6 @@ gdk_wayland_window_create_gl_context (GdkWindow *window,
NULL);
context->egl_config = config;
context->egl_context = ctx;
context->is_attached = attached;
return GDK_GL_CONTEXT (context);

View File

@@ -74,6 +74,7 @@ gdk_win32_gl_context_class_init (GdkWin32GLContextClass *klass)
context_class->end_frame = _gdk_win32_gl_context_end_frame;
context_class->upload_texture = _gdk_win32_gl_context_upload_texture;
context_class->realize = _gdk_win32_gl_context_realize;
gobject_class->dispose = _gdk_win32_gl_context_dispose;
}
@@ -404,7 +405,12 @@ _gdk_win32_display_init_gl (GdkDisplay *display,
}
static HGLRC
_create_gl_context (HDC hdc, GdkGLContext *share, GdkGLProfile profile)
_create_gl_context (HDC hdc,
GdkGLContext *share,
GdkGLProfile profile,
int flags,
int major,
int minor)
{
HGLRC hglrc;
@@ -419,8 +425,9 @@ _create_gl_context (HDC hdc, GdkGLContext *share, GdkGLProfile profile)
gint attribs[] = {
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_MAJOR_VERSION_ARB, major,
WGL_CONTEXT_MINOR_VERSION_ARB, minor,
WGL_CONTEXT_FLAGS_ARB, flags,
0
};
@@ -431,8 +438,8 @@ _create_gl_context (HDC hdc, GdkGLContext *share, GdkGLProfile profile)
context_win32 = GDK_WIN32_GL_CONTEXT (share);
hglrc_32 = wglCreateContextAttribsARB (hdc,
share != NULL ? context_win32->hglrc : NULL,
attribs);
share != NULL ? context_win32->hglrc : NULL,
attribs);
wglMakeCurrent (NULL, NULL);
wglDeleteContext (hglrc);
@@ -441,7 +448,9 @@ _create_gl_context (HDC hdc, GdkGLContext *share, GdkGLProfile profile)
else
{
/* for legacy WGL, we can't share lists during context creation,
* so do so immediately afterwards
* so do so immediately afterwards.
* The flags, and major and minor versions of WGL to request
* for are ignored for a legacy context.
*/
if (share != NULL)
{
@@ -473,6 +482,92 @@ _set_pixformat_for_hdc (HDC hdc,
return TRUE;
}
gboolean
_gdk_win32_gl_context_realize (GdkGLContext *context,
GError **error)
{
GdkGLContext *share = gdk_gl_context_get_shared_context (context);
GdkGLProfile profile = gdk_gl_context_get_profile (context);
GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
/* These are the real WGL context items that we will want to use later */
HGLRC hglrc;
gint pixel_format;
if (!_set_pixformat_for_hdc (context_win32->gl_hdc,
&pixel_format,
context_win32->need_alpha_bits))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
_("No available configurations for the given pixel format"));
return FALSE;
}
if (profile == GDK_GL_PROFILE_DEFAULT)
profile = GDK_GL_PROFILE_3_2_CORE;
if (profile == GDK_GL_PROFILE_3_2_CORE)
{
gboolean debug_bit, compat_bit;
/* request flags and specific versions for core (3.2+) WGL context */
gint flags = 0;
gint glver_major = 0;
gint glver_minor = 0;
gdk_gl_context_get_required_version (context, &glver_major, &glver_minor);
debug_bit = gdk_gl_context_get_debug_enabled (context);
compat_bit = gdk_gl_context_get_forward_compatible (context);
if (debug_bit)
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
if (compat_bit)
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
GDK_NOTE (OPENGL,
g_print ("Creating core WGL context (version:%d.%d, debug:%s, forward:%s)\n",
major, minor,
debug_bit ? "yes" : "no",
compat_bit ? "yes" : "no"));
hglrc = _create_gl_context (context_win32->gl_hdc,
share,
profile,
flags,
glver_major,
glver_minor);
}
else
{
GDK_NOTE (OPENGL, g_print ("Creating legacy WGL context\n"));
/* flags, glver_major, glver_minor are ignored unless we are using WGL 3.2+ core contexts */
hglrc = _create_gl_context (context_win32->gl_hdc,
share,
profile,
0, 0, 0);
}
if (hglrc == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return FALSE;
}
GDK_NOTE (OPENGL,
g_print ("Created WGL context[%p], pixel_format=%d\n",
hglrc,
pixel_format));
context_win32->hglrc = hglrc;
return TRUE;
}
GdkGLContext *
_gdk_win32_window_create_gl_context (GdkWindow *window,
gboolean attached,
@@ -492,11 +587,9 @@ _gdk_win32_window_create_gl_context (GdkWindow *window,
*/
gboolean need_alpha_bits = (visual == gdk_screen_get_rgba_visual (gdk_display_get_default_screen (display)));
/* Real GL Context and Window items */
/* Acquire and store up the Windows-specific HWND and HDC */
HWND hwnd;
HDC hdc;
HGLRC hglrc;
gint pixel_format;
if (!_gdk_win32_display_init_gl (display, need_alpha_bits))
{
@@ -506,6 +599,8 @@ _gdk_win32_window_create_gl_context (GdkWindow *window,
return NULL;
}
/* We first check whether we have WGL_ARB_create_context... */
if (profile == GDK_GL_PROFILE_3_2_CORE &&
!display_win32->hasWglARBCreateContext)
{
@@ -520,36 +615,9 @@ _gdk_win32_window_create_gl_context (GdkWindow *window,
hwnd = GDK_WINDOW_HWND (window);
hdc = GetDC (hwnd);
if (!_set_pixformat_for_hdc (hdc, &pixel_format, need_alpha_bits))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
_("No available configurations for the given pixel format"));
return NULL;
}
if (profile != GDK_GL_PROFILE_3_2_CORE)
profile = GDK_GL_PROFILE_LEGACY;
hglrc = _create_gl_context (hdc, share, profile);
if (hglrc == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return NULL;
}
display_win32->gl_hdc = hdc;
display_win32->gl_hwnd = hwnd;
GDK_NOTE (OPENGL,
g_print ("Created WGL context[%p], pixel_format=%d\n",
hglrc,
pixel_format));
context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT,
"display", display,
"window", window,
@@ -557,7 +625,7 @@ _gdk_win32_window_create_gl_context (GdkWindow *window,
"shared-context", share,
NULL);
context->hglrc = hglrc;
context->need_alpha_bits = need_alpha_bits;
context->gl_hdc = hdc;
context->is_attached = attached;

View File

@@ -40,6 +40,7 @@ struct _GdkWin32GLContext
/* WGL Context Items */
HGLRC hglrc;
HDC gl_hdc;
guint need_alpha_bits : 1;
/* other items */
guint is_attached : 1;
@@ -79,6 +80,10 @@ gboolean
_gdk_win32_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context);
gboolean
_gdk_win32_gl_context_realize (GdkGLContext *context,
GError **error);
G_END_DECLS
#endif /* __GDK_WIN32_GL_CONTEXT__ */

View File

@@ -534,6 +534,180 @@ gdk_x11_gl_context_texture_from_surface (GdkGLContext *paint_context,
return TRUE;
}
static XVisualInfo *
find_xvisinfo_for_fbconfig (GdkDisplay *display,
GLXFBConfig config)
{
Display *dpy = gdk_x11_display_get_xdisplay (display);
return glXGetVisualFromFBConfig (dpy, config);
}
static GLXContext
create_gl3_context (GdkDisplay *display,
GLXFBConfig config,
GdkGLContext *share,
int flags,
int major,
int minor)
{
int attrib_list[] = {
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_MAJOR_VERSION_ARB, major,
GLX_CONTEXT_MINOR_VERSION_ARB, minor,
GLX_CONTEXT_FLAGS_ARB, flags,
None,
};
GdkX11GLContext *share_x11 = NULL;
if (share != NULL)
share_x11 = GDK_X11_GL_CONTEXT (share);
return glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
config,
share_x11 != NULL ? share_x11->glx_context : NULL,
True,
attrib_list);
}
static gboolean
gdk_x11_gl_context_realize (GdkGLContext *context,
GError **error)
{
GdkDisplay *display;
GdkX11GLContext *context_x11;
GLXWindow drawable;
XVisualInfo *xvisinfo;
Display *dpy;
DrawableInfo *info;
GdkGLProfile profile;
GdkGLContext *share;
GdkWindow *window;
window = gdk_gl_context_get_window (context);
display = gdk_window_get_display (window);
dpy = gdk_x11_display_get_xdisplay (display);
context_x11 = GDK_X11_GL_CONTEXT (context);
profile = gdk_gl_context_get_profile (context);
share = gdk_gl_context_get_shared_context (context);
/* we check for the presence of the GLX_ARB_create_context_profile
* extension before checking for a GLXFBConfig.
*/
if (profile == GDK_GL_PROFILE_3_2_CORE)
{
gboolean debug_bit, compat_bit;
int major, minor, flags;
gdk_gl_context_get_required_version (context, &major, &minor);
debug_bit = gdk_gl_context_get_debug_enabled (context);
compat_bit = gdk_gl_context_get_forward_compatible (context);
flags = 0;
if (debug_bit)
flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
if (compat_bit)
flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
GDK_NOTE (OPENGL,
g_print ("Creating core GLX context (version:%d.%d, debug:%s, forward:%s)\n",
major, minor,
debug_bit ? "yes" : "no",
compat_bit ? "yes" : "no"));
context_x11->glx_context = create_gl3_context (display,
context_x11->glx_config,
share,
flags, major, minor);
}
else
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_UNSUPPORTED_PROFILE,
_("Unsupported profile for a GL context"));
return FALSE;
}
if (context_x11->glx_context == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return FALSE;
}
xvisinfo = find_xvisinfo_for_fbconfig (display, context_x11->glx_config);
info = get_glx_drawable_info (window->impl_window);
if (info == NULL)
{
XSetWindowAttributes attrs;
unsigned long mask;
gdk_x11_display_error_trap_push (display);
info = g_slice_new0 (DrawableInfo);
info->display = display;
info->last_frame_counter = 0;
attrs.override_redirect = True;
attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
attrs.border_pixel = 0;
mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
info->dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
-100, -100, 1, 1,
0,
xvisinfo->depth,
CopyFromParent,
xvisinfo->visual,
mask,
&attrs);
XMapWindow(dpy, info->dummy_xwin);
if (GDK_X11_DISPLAY (display)->glx_version >= 13)
{
info->glx_drawable = glXCreateWindow (dpy, context_x11->glx_config,
gdk_x11_window_get_xid (window->impl_window),
NULL);
info->dummy_glx = glXCreateWindow (dpy, context_x11->glx_config, info->dummy_xwin, NULL);
}
if (gdk_x11_display_error_trap_pop (display))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
XFree (xvisinfo);
drawable_info_free (info);
glXDestroyContext (dpy, context_x11->glx_context);
context_x11->glx_context = NULL;
return FALSE;
}
set_glx_drawable_info (window->impl_window, info);
}
XFree (xvisinfo);
if (context_x11->is_attached)
drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_window_get_xid (window->impl_window);
else
drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
context_x11->is_direct = glXIsDirect (dpy, context_x11->glx_context);
context_x11->drawable = drawable;
GDK_NOTE (OPENGL,
g_print ("Realized GLX context[%p], %s\n",
context_x11->glx_context,
context_x11->is_direct ? "direct" : "indirect"));
return TRUE;
}
static void
gdk_x11_gl_context_dispose (GObject *gobject)
{
@@ -562,6 +736,7 @@ gdk_x11_gl_context_class_init (GdkX11GLContextClass *klass)
GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
context_class->realize = gdk_x11_gl_context_realize;
context_class->end_frame = gdk_x11_gl_context_end_frame;
context_class->texture_from_surface = gdk_x11_gl_context_texture_from_surface;
@@ -645,11 +820,10 @@ gdk_x11_screen_init_gl (GdkScreen *screen)
#define MAX_GLX_ATTRS 30
static gboolean
find_fbconfig_for_visual (GdkDisplay *display,
GdkVisual *visual,
GLXFBConfig *fb_config_out,
XVisualInfo **visinfo_out,
GError **error)
find_fbconfig_for_visual (GdkDisplay *display,
GdkVisual *visual,
GLXFBConfig *fb_config_out,
GError **error)
{
static int attrs[MAX_GLX_ATTRS];
Display *dpy = gdk_x11_display_get_xdisplay (display);
@@ -710,16 +884,15 @@ find_fbconfig_for_visual (GdkDisplay *display,
continue;
if (visinfo->visualid != xvisual_id)
continue;
{
XFree (visinfo);
continue;
}
if (fb_config_out != NULL)
*fb_config_out = configs[i];
if (visinfo_out != NULL)
*visinfo_out = visinfo;
else
XFree (visinfo);
XFree (visinfo);
retval = TRUE;
goto out;
}
@@ -734,58 +907,6 @@ out:
return retval;
}
static GLXContext
create_gl3_context (GdkDisplay *display,
GLXFBConfig config,
GdkGLContext *share)
{
/* There are no profiles before OpenGL 3.2.
*
* The GLX_ARB_create_context_profile spec says:
*
* If the requested OpenGL version is less than 3.2,
* GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
* of the context is determined solely by the requested version.
*
* Which means we can ask for the CORE_PROFILE_BIT without asking for
* a 3.2 version.
*/
static const int attrib_list[] = {
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_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);
}
struct glvisualinfo {
int supports_gl;
int double_buffer;
@@ -951,12 +1072,13 @@ save_cached_gl_visuals (GdkDisplay *display, int system, int rgba)
visualdata[1] = rgba;
gdk_x11_display_error_trap_push (display);
XChangeProperty(dpy, DefaultRootWindow (dpy), gdk_x11_get_xatom_by_name_for_display (display, "GDK_VISUALS"),
XA_INTEGER, 32, PropModeReplace, (unsigned char *)visualdata, 2);
XChangeProperty (dpy, DefaultRootWindow (dpy),
gdk_x11_get_xatom_by_name_for_display (display, "GDK_VISUALS"),
XA_INTEGER, 32, PropModeReplace,
(unsigned char *)visualdata, 2);
gdk_x11_display_error_trap_pop_ignored (display);
}
void
_gdk_x11_screen_update_visuals_for_gl (GdkScreen *screen)
{
@@ -1038,27 +1160,24 @@ _gdk_x11_screen_update_visuals_for_gl (GdkScreen *screen)
x11_screen->rgba_visual ? gdk_x11_visual_get_xvisual (x11_screen->rgba_visual)->visualid : 0);
}
GdkGLContext *
gdk_x11_window_create_gl_context (GdkWindow *window,
gboolean attached,
GdkGLProfile profile,
GdkGLContext *share,
GError **error)
gboolean attached,
GdkGLProfile profile,
GdkGLContext *share,
GError **error)
{
GdkDisplay *display;
GdkX11GLContext *context;
GdkVisual *visual;
GLXFBConfig config;
GLXContext glx_context;
GLXWindow drawable;
gboolean is_direct;
XVisualInfo *xvisinfo;
Display *dpy;
DrawableInfo *info;
display = gdk_window_get_display (window);
/* GDK_GL_PROFILE_DEFAULT is currently equivalent to the 3_2_CORE profile */
if (profile == GDK_GL_PROFILE_DEFAULT)
profile = GDK_GL_PROFILE_3_2_CORE;
if (!gdk_x11_screen_init_gl (gdk_window_get_screen (window)))
{
g_set_error_literal (error, GDK_GL_ERROR,
@@ -1079,101 +1198,9 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
}
visual = gdk_window_get_visual (window);
if (!find_fbconfig_for_visual (display, visual, &config, &xvisinfo, error))
if (!find_fbconfig_for_visual (display, visual, &config, error))
return NULL;
dpy = gdk_x11_display_get_xdisplay (display);
/* we check for the presence of the GLX_ARB_create_context_profile
* extension before checking for a GLXFBConfig.
*/
if (profile == GDK_GL_PROFILE_3_2_CORE)
{
GDK_NOTE (OPENGL, g_print ("Creating core GLX context\n"));
glx_context = create_gl3_context (display, config, share);
}
else
{
/* GDK_GL_PROFILE_DEFAULT is currently
* equivalent to the LEGACY profile
*/
profile = GDK_GL_PROFILE_LEGACY;
GDK_NOTE (OPENGL, g_print ("Creating legacy GLX context\n"));
glx_context = create_gl_context (display, config, share);
}
if (glx_context == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return NULL;
}
is_direct = glXIsDirect (dpy, glx_context);
info = get_glx_drawable_info (window->impl_window);
if (info == NULL)
{
XSetWindowAttributes attrs;
unsigned long mask;
gdk_x11_display_error_trap_push (display);
info = g_slice_new0 (DrawableInfo);
info->display = display;
info->last_frame_counter = 0;
attrs.override_redirect = True;
attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
attrs.border_pixel = 0;
mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
info->dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
-100, -100, 1, 1,
0,
xvisinfo->depth,
CopyFromParent,
xvisinfo->visual,
mask,
&attrs);
XMapWindow(dpy, info->dummy_xwin);
if (GDK_X11_DISPLAY (display)->glx_version >= 13)
{
info->glx_drawable = glXCreateWindow (dpy, config,
gdk_x11_window_get_xid (window->impl_window),
NULL);
info->dummy_glx = glXCreateWindow (dpy, config, info->dummy_xwin, NULL);
}
if (gdk_x11_display_error_trap_pop (display))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
drawable_info_free (info);
glXDestroyContext (dpy, glx_context);
return NULL;
}
set_glx_drawable_info (window->impl_window, info);
}
XFree (xvisinfo);
if (attached)
drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_window_get_xid (window->impl_window);
else
drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
GDK_NOTE (OPENGL,
g_print ("Created GLX context[%p], %s\n",
glx_context,
is_direct ? "direct" : "indirect"));
context = g_object_new (GDK_TYPE_X11_GL_CONTEXT,
"display", display,
"window", window,
@@ -1183,10 +1210,7 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
context->profile = profile;
context->glx_config = config;
context->glx_context = glx_context;
context->drawable = drawable;
context->is_attached = attached;
context->is_direct = is_direct;
return GDK_GL_CONTEXT (context);
}

View File

@@ -322,8 +322,21 @@ gtk_gl_area_real_create_context (GtkGLArea *area)
GError *error = NULL;
GdkGLContext *context;
context = gdk_window_create_gl_context (gtk_widget_get_window (widget), priv->profile, &priv->error);
gtk_gl_area_set_error (area, error);
context = gdk_window_create_gl_context (gtk_widget_get_window (widget), priv->profile, &error);
if (priv->error != NULL)
{
gtk_gl_area_set_error (area, error);
g_clear_object (&context);
return NULL;
}
gdk_gl_context_realize (context, &error);
if (priv->error != NULL)
{
gtk_gl_area_set_error (area, error);
g_clear_object (&context);
return NULL;
}
return context;
}
@@ -426,17 +439,17 @@ gtk_gl_area_allocate_buffers (GtkGLArea *area)
if (priv->render_buffer)
{
glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, priv->render_buffer);
glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_RGB8, width, height);
glBindRenderbuffer (GL_RENDERBUFFER, priv->render_buffer);
glRenderbufferStorage (GL_RENDERBUFFER, GL_RGB8, width, height);
}
if (priv->has_depth_buffer || priv->has_stencil_buffer)
{
glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, priv->depth_stencil_buffer);
glBindRenderbuffer (GL_RENDERBUFFER, priv->depth_stencil_buffer);
if (priv->has_stencil_buffer)
glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, width, height);
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
else
glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
}
priv->needs_render = TRUE;

View File

@@ -1,3 +1,4 @@
#include <math.h>
#include <stdlib.h>
#include <gtk/gtk.h>
@@ -15,17 +16,244 @@ static float rotation_angles[N_AXIS] = { 0.0 };
static GtkWidget *gl_area;
static const GLfloat vertex_data[] = {
0.f, 0.5f, 0.f, 1.f,
0.5f, -0.366f, 0.f, 1.f,
-0.5f, -0.366f, 0.f, 1.f,
};
static void
init_buffers (GLuint *vao_out,
GLuint *buffer_out)
{
GLuint vao, buffer;
/* we only use one VAO, so we always keep it bound */
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
glGenBuffers (1, &buffer);
glBindBuffer (GL_ARRAY_BUFFER, buffer);
glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data, GL_STATIC_DRAW);
glBindBuffer (GL_ARRAY_BUFFER, 0);
if (vao_out != NULL)
*vao_out = vao;
if (buffer_out != NULL)
*buffer_out = buffer;
}
static GLuint
create_shader (int type, const char *src)
{
GLuint shader;
int status;
shader = glCreateShader (type);
glShaderSource (shader, 1, &src, NULL);
glCompileShader (shader);
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
int log_len;
char *buffer;
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc (log_len + 1);
glGetShaderInfoLog (shader, log_len, NULL, buffer);
g_warning ("Compile failure in %s shader:\n%s\n",
type == GL_VERTEX_SHADER ? "vertex" : "fragment",
buffer);
g_free (buffer);
glDeleteShader (shader);
return 0;
}
return shader;
}
static const char *vertex_shader_code =
"#version 330\n" \
"\n" \
"layout(location = 0) in vec4 position;\n" \
"uniform mat4 mvp;\n"
"void main() {\n" \
" gl_Position = mvp * position;\n" \
"}";
static const char *fragment_shader_code =
"#version 330\n" \
"\n" \
"out vec4 outputColor;\n" \
"void main() {\n" \
" float lerpVal = gl_FragCoord.y / 400.0f;\n" \
" outputColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpVal);\n" \
"}";
static void
init_shaders (GLuint *program_out,
GLuint *mvp_out)
{
GLuint vertex, fragment;
GLuint program = 0;
GLuint mvp = 0;
int status;
vertex = create_shader (GL_VERTEX_SHADER, vertex_shader_code);
if (vertex == 0)
{
*program_out = 0;
return;
}
fragment = create_shader (GL_FRAGMENT_SHADER, fragment_shader_code);
if (fragment == 0)
{
glDeleteShader (vertex);
*program_out = 0;
return;
}
program = glCreateProgram ();
glAttachShader (program, vertex);
glAttachShader (program, fragment);
glLinkProgram (program);
glGetProgramiv (program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
int log_len;
char *buffer;
glGetProgramiv (program, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc (log_len + 1);
glGetProgramInfoLog (program, log_len, NULL, buffer);
g_warning ("Linking failure:\n%s\n", buffer);
g_free (buffer);
glDeleteProgram (program);
program = 0;
goto out;
}
mvp = glGetUniformLocation (program, "mvp");
glDetachShader (program, vertex);
glDetachShader (program, fragment);
out:
glDeleteShader (vertex);
glDeleteShader (fragment);
if (program_out != NULL)
*program_out = program;
if (mvp_out != NULL)
*mvp_out = mvp;
}
static void
compute_mvp (float *res,
float phi,
float theta,
float psi)
{
float x = phi * (G_PI / 180.f);
float y = theta * (G_PI / 180.f);
float z = psi * (G_PI / 180.f);
float c1 = cosf (x), s1 = sinf (x);
float c2 = cosf (y), s2 = sinf (y);
float c3 = cosf (z), s3 = sinf (z);
float c3c2 = c3 * c2;
float s3c1 = s3 * c1;
float c3s2s1 = c3 * s2 * s1;
float s3s1 = s3 * s1;
float c3s2c1 = c3 * s2 * c1;
float s3c2 = s3 * c2;
float c3c1 = c3 * c1;
float s3s2s1 = s3 * s2 * s1;
float c3s1 = c3 * s1;
float s3s2c1 = s3 * s2 * c1;
float c2s1 = c2 * s1;
float c2c1 = c2 * c1;
/* initialize to the identity matrix */
res[0] = 1.f; res[4] = 0.f; res[8] = 0.f; res[12] = 0.f;
res[1] = 0.f; res[5] = 1.f; res[9] = 0.f; res[13] = 0.f;
res[2] = 0.f; res[6] = 0.f; res[10] = 1.f; res[14] = 0.f;
res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f;
/* apply all three rotations using the three matrices:
*
* ⎡ c3 s3 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ 1 0 0 ⎤
* ⎢ -s3 c3 0 ⎥ ⎢ 0 1 0 ⎥ ⎢ 0 c1 s1 ⎥
* ⎣ 0 0 1 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 -s1 c1 ⎦
*/
res[0] = c3c2; res[4] = s3c1 + c3s2s1; res[8] = s3s1 - c3s2c1; res[12] = 0.f;
res[1] = -s3c2; res[5] = c3c1 - s3s2s1; res[9] = c3s1 + s3s2c1; res[13] = 0.f;
res[2] = s2; res[6] = -c2s1; res[10] = c2c1; res[14] = 0.f;
res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f;
}
static GLuint position_buffer;
static GLuint program;
static GLuint mvp_location;
static void
realize (GtkWidget *widget)
{
gtk_gl_area_make_current (GTK_GL_AREA (widget));
init_buffers (&position_buffer, NULL);
init_shaders (&program, &mvp_location);
}
static void
unrealize (GtkWidget *widget)
{
gtk_gl_area_make_current (GTK_GL_AREA (widget));
glDeleteBuffers (1, &position_buffer);
glDeleteProgram (program);
}
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 ();
float mvp[16];
g_assert (position_buffer != 0);
g_assert (program != 0);
compute_mvp (mvp,
rotation_angles[X_AXIS],
rotation_angles[Y_AXIS],
rotation_angles[Z_AXIS]);
glUseProgram (program);
glUniformMatrix4fv (mvp_location, 1, GL_FALSE, &mvp[0]);
glBindBuffer (GL_ARRAY_BUFFER, position_buffer);
glEnableVertexAttribArray (0);
glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays (GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray (0);
glUseProgram (0);
}
static gboolean
@@ -35,12 +263,6 @@ render (GtkGLArea *area,
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 ();
@@ -120,8 +342,8 @@ main (int argc, char *argv[])
*/
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_window_set_title (GTK_WINDOW (window), "GtkGLArea - Triangle");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
gtk_container_set_border_width (GTK_CONTAINER (window), 12);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
@@ -134,6 +356,8 @@ main (int argc, char *argv[])
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 (realize), NULL);
g_signal_connect (gl_area, "unrealize", G_CALLBACK (unrealize), NULL);
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
gtk_widget_show (gl_area);