Compare commits
20 Commits
matthiasc/
...
wip/ebassi
Author | SHA1 | Date | |
---|---|---|---|
|
1b0b2c1e39 | ||
|
8eb58dc557 | ||
|
c3c338dcc0 | ||
|
9f28994f10 | ||
|
c4df6af425 | ||
|
5043eeaf3e | ||
|
1102d047b6 | ||
|
ab7d8c3044 | ||
|
d9ecc88728 | ||
|
cfdfa1c9be | ||
|
3ff6a71923 | ||
|
8846a7002c | ||
|
bd26ebde63 | ||
|
4bf387eb37 | ||
|
7976c7c80b | ||
|
26390d0bbc | ||
|
52570ed5ff | ||
|
e9276c1080 | ||
|
dd4fdea535 | ||
|
4b08b9f239 |
@@ -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 \
|
||||
|
@@ -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>
|
||||
|
9
demos/gtk-demo/glarea-fragment.glsl
Normal file
9
demos/gtk-demo/glarea-fragment.glsl
Normal 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);
|
||||
}
|
8
demos/gtk-demo/glarea-vertex.glsl
Normal file
8
demos/gtk-demo/glarea-vertex.glsl
Normal file
@@ -0,0 +1,8 @@
|
||||
#version 330
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
uniform mat4 mvp;
|
||||
|
||||
void main() {
|
||||
gl_Position = mvp * position;
|
||||
}
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -1116,7 +1116,6 @@ GdkGLContext * gdk_window_create_gl_context (GdkWindow *window,
|
||||
GdkGLProfile profile,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_WINDOW_H__ */
|
||||
|
@@ -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__ */
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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__ */
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user