[gtk+] gdk_gl_texture_quad: Use shaders to texture things



commit e417b18373bfcbf0c4f1bd933450a2ed3203017e
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Nov 6 09:13:36 2014 +0100

    gdk_gl_texture_quad: Use shaders to texture things
    
    This is the modern way OpenGL works, and using it will let us
    switch to a core context for the paint context, and work on
    OpenGL ES 2.0.

 gdk/gdkgl.c                |  202 ++++++++++++++++++++++++++++++++++++++++----
 gdk/gdkglcontextprivate.h  |    7 ++
 gdk/gdkinternals.h         |    3 +-
 gdk/x11/gdkglcontext-x11.c |    3 +-
 4 files changed, 197 insertions(+), 18 deletions(-)
---
diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c
index 8f7d394..a41d886 100644
--- a/gdk/gdkgl.c
+++ b/gdk/gdkgl.c
@@ -35,25 +35,193 @@ gdk_cairo_surface_mark_as_direct (cairo_surface_t *surface,
                                g_object_ref (window),  g_object_unref);
 }
 
+static const char *
+get_vertex_type_name (int type)
+{
+  switch (type)
+    {
+    case GL_VERTEX_SHADER:
+      return "vertex";
+    case GL_GEOMETRY_SHADER:
+      return "geometry";
+    case GL_FRAGMENT_SHADER:
+      return "fragment";
+    }
+  return "unknown";
+}
+
+guint
+create_shader (int type, const char const *code)
+{
+  guint shader;
+  int status;
+
+  shader = glCreateShader (type);
+  glShaderSource (shader, 1, &code, 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", get_vertex_type_name (type), buffer);
+      g_free (buffer);
+
+      glDeleteShader (shader);
+
+      return 0;
+    }
+
+  return shader;
+}
+
+guint
+make_program (const char const *vertex_shader_code, const char const *fragment_shader_code)
+{
+  guint program, vertex_shader, fragment_shader;
+  int status;
+
+  vertex_shader = create_shader (GL_VERTEX_SHADER, vertex_shader_code);
+  if (vertex_shader == 0)
+    return 0;
+
+  fragment_shader = create_shader (GL_FRAGMENT_SHADER, fragment_shader_code);
+  if (fragment_shader == 0)
+    {
+      glDeleteShader (vertex_shader);
+      return 0;
+    }
+
+  program = glCreateProgram ();
+  glAttachShader (program, vertex_shader);
+  glAttachShader (program, fragment_shader);
+
+  glLinkProgram (program);
+
+  glDeleteShader (vertex_shader);
+  glDeleteShader (fragment_shader);
+
+  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 ("Linker failure: %s\n", buffer);
+      g_free (buffer);
+
+      glDeleteProgram (program);
+      return 0;
+    }
+
+  return program;
+}
+
+static void
+bind_vao (GdkGLContextPaintData *paint_data)
+{
+  if (paint_data->vertex_array_object == 0)
+    {
+      glGenVertexArrays (1, &paint_data->vertex_array_object);
+      /* ATM we only use one VAO, so always bind it */
+      glBindVertexArray (paint_data->vertex_array_object);
+    }
+}
+
+static void
+use_texture_program (GdkGLContextPaintData *paint_data)
+{
+  const char *vertex_shader_code =
+    "#version 120\n"
+    "uniform sampler2D map;"
+    "attribute vec2 position;\n"
+    "attribute vec2 uv;\n"
+    "varying vec2 vUv;\n"
+    "void main() {\n"
+    "  gl_Position = vec4(position, 0, 1);\n"
+    "  vUv = uv;\n"
+    "}\n";
+  const char *fragment_shader_code =
+    "#version 120\n"
+    "varying vec2 vUv;\n"
+    "uniform sampler2D map;\n"
+    "void main() {\n"
+    "  gl_FragColor = texture2D (map, vUv);\n"
+    "}\n";
+
+  if (paint_data->texture_quad_program == 0)
+    {
+      paint_data->texture_quad_program = make_program (vertex_shader_code, fragment_shader_code);
+      paint_data->texture_quad_program_position_location = glGetAttribLocation 
(paint_data->texture_quad_program, "position");
+      paint_data->texture_quad_program_uv_location = glGetAttribLocation (paint_data->texture_quad_program, 
"uv");
+    }
+
+  if (paint_data->current_program != paint_data->texture_quad_program)
+    {
+      glUseProgram (paint_data->texture_quad_program);
+      paint_data->current_program = paint_data->texture_quad_program;
+    }
+}
+
 void
-gdk_gl_texture_quad (float x1, float y1,
+gdk_gl_texture_quad (GdkGLContext *paint_context,
+                     float x1, float y1,
                      float x2, float y2,
                      float u1, float v1,
                      float u2, float v2)
 {
-  glBegin (GL_QUADS);
-  glTexCoord2f (u1, v2);
-  glVertex2f (x1, y2);
-
-  glTexCoord2f (u2, v2);
-  glVertex2f (x2, y2);
-
-  glTexCoord2f (u2, v1);
-  glVertex2f (x2, y1);
-
-  glTexCoord2f (u1, v1);
-  glVertex2f (x1, y1);
-  glEnd();
+  GdkGLContextPaintData *paint_data  = gdk_gl_context_get_paint_data (paint_context);;
+  GdkWindow *window = gdk_gl_context_get_window (paint_context);
+  float w = gdk_window_get_width (window);
+  float h = gdk_window_get_height (window);
+  float vertex_buffer_data[] = {
+    (x2 * 2) / w - 1, (y1 * 2) / h - 1,
+    (x2 * 2) / w - 1, (y2 * 2) / h - 1,
+    (x1 * 2) / w - 1, (y2 * 2) / h - 1,
+    (x1 * 2) / w - 1, (y1 * 2) / h - 1,
+  };
+  float uv_buffer_data[] = {
+    u2, v1,
+    u2, v2,
+    u1, v2,
+    u1, v1,
+  };
+
+  bind_vao (paint_data);
+
+  if (paint_data->tmp_vertex_buffer == 0)
+    glGenBuffers(1, &paint_data->tmp_vertex_buffer);
+
+  if (paint_data->tmp_uv_buffer == 0)
+    glGenBuffers(1, &paint_data->tmp_uv_buffer);
+
+  use_texture_program (paint_data);
+
+  glActiveTexture (GL_TEXTURE0);
+  glEnableVertexAttribArray (0);
+  glBindBuffer (GL_ARRAY_BUFFER, paint_data->tmp_vertex_buffer);
+  glBufferData (GL_ARRAY_BUFFER, sizeof(vertex_buffer_data), vertex_buffer_data, GL_STREAM_DRAW);
+  glVertexAttribPointer (paint_data->texture_quad_program_position_location,
+                         2, GL_FLOAT, GL_FALSE, 0, NULL);
+  glEnableVertexAttribArray (1);
+  glBindBuffer (GL_ARRAY_BUFFER, paint_data->tmp_uv_buffer);
+  glBufferData (GL_ARRAY_BUFFER, sizeof(uv_buffer_data), uv_buffer_data, GL_STREAM_DRAW);
+  glVertexAttribPointer (paint_data->texture_quad_program_uv_location,
+                         2, GL_FLOAT, GL_FALSE, 0, NULL);
+  glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+  glDisableVertexAttribArray (0);
+  glDisableVertexAttribArray (1);
 }
 
 
@@ -328,7 +496,8 @@ gdk_cairo_draw_from_gl (cairo_t              *cr,
               int clipped_src_x = x + (dest.x - dx * window_scale);
               int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale));
 
-              gdk_gl_texture_quad (dest.x, FLIP_Y(dest.y),
+              gdk_gl_texture_quad (paint_context,
+                                   dest.x, FLIP_Y(dest.y),
                                    dest.x + dest.width, FLIP_Y(dest.y + dest.height),
                                    clipped_src_x / (float)texture_width, (clipped_src_y + dest.height) / 
(float)texture_height,
                                    (clipped_src_x + dest.width) / (float)texture_width, clipped_src_y / 
(float)texture_height);
@@ -507,7 +676,8 @@ gdk_gl_texture_from_surface (cairo_surface_t *surface,
           vmax = 1.0;
         }
 
-      gdk_gl_texture_quad (rect.x * window_scale, FLIP_Y(rect.y) * window_scale,
+      gdk_gl_texture_quad (paint_context,
+                           rect.x * window_scale, FLIP_Y(rect.y) * window_scale,
                            (rect.x + rect.width) * window_scale, FLIP_Y(rect.y + rect.height) * window_scale,
                            0, 0,
                            umax, vmax);
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index cf6e578..c738fa5 100644
--- a/gdk/gdkglcontextprivate.h
+++ b/gdk/gdkglcontextprivate.h
@@ -57,7 +57,14 @@ void            gdk_gl_context_end_frame (GdkGLContext *context,
 
 
 typedef struct {
+  guint vertex_array_object;
   guint tmp_framebuffer;
+  guint tmp_vertex_buffer;
+  guint tmp_uv_buffer;
+  guint current_program;
+  guint texture_quad_program;
+  guint texture_quad_program_position_location;
+  guint texture_quad_program_uv_location;
 } GdkGLContextPaintData;
 
 GdkGLContextPaintData *gdk_gl_context_get_paint_data (GdkGLContext *context);
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 69be704..0132cd8 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -341,7 +341,8 @@ gboolean        _gdk_cairo_surface_extents       (cairo_surface_t *surface,
                                                   GdkRectangle    *extents);
 void            gdk_gl_texture_from_surface      (cairo_surface_t *surface,
                                                   cairo_region_t  *region);
-void           gdk_gl_texture_quad               (float x1, float y1,
+void           gdk_gl_texture_quad               (GdkGLContext *paint_context,
+                                                  float x1, float y1,
                                                   float x2, float y2,
                                                   float u1, float v1,
                                                   float u2, float v2);
diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c
index 87724d7..a0258b9 100644
--- a/gdk/x11/gdkglcontext-x11.c
+++ b/gdk/x11/gdkglcontext-x11.c
@@ -466,7 +466,8 @@ gdk_x11_gl_context_texture_from_surface (GdkGLContext *paint_context,
           vscale = 1.0 / cairo_xlib_surface_get_height (surface);
         }
 
-      gdk_gl_texture_quad (rect.x * window_scale, FLIP_Y(rect.y) * window_scale,
+      gdk_gl_texture_quad (paint_context,
+                           rect.x * window_scale, FLIP_Y(rect.y) * window_scale,
                            (rect.x + rect.width) * window_scale, FLIP_Y(rect.y + rect.height) * window_scale,
                            uscale * src_x, vscale * src_y,
                            uscale * (src_x + src_width), vscale * (src_y + src_height));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]