[gtk+/wip/ebassi/gsk-renderer: 37/58] gsk: Add GskGLDriver



commit 138e9729c7cc3242907f5379b4fbaab41aa11056
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Fri Jul 8 16:21:13 2016 +0100

    gsk: Add GskGLDriver
    
    We can move the caching and management of textures, VAOs, and state of
    the GL machinery into a single object, GskGLDriver.

 gsk/Makefile.am          |    2 +
 gsk/gskgldriver.c        |  369 ++++++++++++++++++++++++++++++++++++++++++++++
 gsk/gskgldriverprivate.h |   45 ++++++
 gsk/gskglrenderer.c      |  219 +++++++++------------------
 4 files changed, 487 insertions(+), 148 deletions(-)
---
diff --git a/gsk/Makefile.am b/gsk/Makefile.am
index 7edabe3..3f5f4d1 100644
--- a/gsk/Makefile.am
+++ b/gsk/Makefile.am
@@ -36,6 +36,7 @@ gsk_public_source_h = \
 gsk_private_source_h = \
        gskcairorendererprivate.h \
        gskdebugprivate.h \
+       gskgldriverprivate.h \
        gskglrendererprivate.h \
        gskprivate.h \
        gskrendererprivate.h \
@@ -52,6 +53,7 @@ gsk_built_source_c = \
 gsk_source_c = \
        gskcairorenderer.c \
        gskdebug.c \
+       gskgldriver.c \
        gskglrenderer.c \
        gskrenderer.c \
        gskrendernode.c \
diff --git a/gsk/gskgldriver.c b/gsk/gskgldriver.c
new file mode 100644
index 0000000..0ed1493
--- /dev/null
+++ b/gsk/gskgldriver.c
@@ -0,0 +1,369 @@
+#include "config.h"
+
+#include "gskgldriverprivate.h"
+
+#include "gskdebugprivate.h"
+
+#include <gdk/gdk.h>
+#include <epoxy/gl.h>
+
+typedef struct {
+  GLuint texture_id;
+  int width;
+  int height;
+} Texture;
+
+typedef struct {
+  GLuint vao_id;
+  GLuint buffer_id;
+  GLuint position_id;
+  GLuint uv_id;
+} Vao;
+
+struct _GskGLDriver
+{
+  GObject parent_instance;
+
+  GdkGLContext *gl_context;
+
+  GArray *textures;
+  GArray *vaos;
+
+  Texture *bound_source_texture;
+  Texture *bound_mask_texture;
+  Vao *bound_vao;
+
+  gboolean in_frame : 1;
+};
+
+enum
+{
+  PROP_GL_CONTEXT = 1,
+
+  N_PROPS
+};
+
+static GParamSpec *gsk_gl_driver_properties[N_PROPS];
+
+G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
+
+static void
+texture_clear (gpointer data)
+{
+  Texture *t = data;
+
+  glDeleteTextures (1, &t->texture_id);
+}
+
+static void
+vao_clear (gpointer data)
+{
+  Vao *v = data;
+
+  glDeleteBuffers (1, &v->buffer_id);
+  glDeleteVertexArrays (1, &v->vao_id);
+}
+
+static void
+gsk_gl_driver_finalize (GObject *gobject)
+{
+  GskGLDriver *self = GSK_GL_DRIVER (gobject);
+
+  g_clear_pointer (&self->textures, g_array_unref);
+  g_clear_pointer (&self->vaos, g_array_unref);
+
+  g_clear_object (&self->gl_context);
+
+  G_OBJECT_CLASS (gsk_gl_driver_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_gl_driver_set_property (GObject      *gobject,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  GskGLDriver *self = GSK_GL_DRIVER (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_GL_CONTEXT:
+      self->gl_context = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gsk_gl_driver_get_property (GObject    *gobject,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  GskGLDriver *self = GSK_GL_DRIVER (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_GL_CONTEXT:
+      g_value_set_object (value, self->gl_context);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gsk_gl_driver_class_init (GskGLDriverClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gsk_gl_driver_set_property;
+  gobject_class->get_property = gsk_gl_driver_get_property;
+  gobject_class->finalize = gsk_gl_driver_finalize;
+
+  gsk_gl_driver_properties[PROP_GL_CONTEXT] =
+    g_param_spec_object ("gl-context", "GL Context", "The GL context used by the driver",
+                         GDK_TYPE_GL_CONTEXT,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, gsk_gl_driver_properties);
+}
+
+static void
+gsk_gl_driver_init (GskGLDriver *self)
+{
+  self->textures = g_array_new (FALSE, FALSE, sizeof (Texture));
+  g_array_set_clear_func (self->textures, texture_clear);
+
+  self->vaos = g_array_new (FALSE, FALSE, sizeof (Vao));
+  g_array_set_clear_func (self->vaos, vao_clear);
+}
+
+GskGLDriver *
+gsk_gl_driver_new (GdkGLContext *context)
+{
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+  return g_object_new (GSK_TYPE_GL_DRIVER,
+                       "gl-context", context,
+                       NULL);
+}
+
+void
+gsk_gl_driver_begin_frame (GskGLDriver *driver)
+{
+  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
+  g_return_if_fail (!driver->in_frame);
+
+  driver->in_frame = TRUE;
+
+  glActiveTexture (GL_TEXTURE0);
+  glBindTexture (GL_TEXTURE_2D, 0);
+
+  glActiveTexture (GL_TEXTURE0 + 1);
+  glBindTexture (GL_TEXTURE_2D, 0);
+
+  glBindVertexArray (0);
+  glUseProgram (0);
+
+  glActiveTexture (GL_TEXTURE0);
+}
+
+void
+gsk_gl_driver_end_frame (GskGLDriver *driver)
+{
+  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
+  g_return_if_fail (driver->in_frame);
+
+  glBindTexture (GL_TEXTURE_2D, 0);
+  glUseProgram (0);
+  glBindVertexArray (0);
+
+  driver->bound_source_texture = NULL;
+  driver->bound_mask_texture = NULL;
+  driver->bound_vao = NULL;
+
+  g_array_set_size (driver->textures, 0);
+  g_array_set_size (driver->vaos, 0);
+
+  driver->in_frame = FALSE;
+}
+
+int
+gsk_gl_driver_create_texture (GskGLDriver     *driver,
+                              int              width,
+                              int              height,
+                              int              min_filter,
+                              int              mag_filter,
+                              cairo_surface_t *surface)
+{
+  guint texture_id;
+  Texture t;
+
+  glGenTextures (1, &texture_id);
+  glBindTexture (GL_TEXTURE_2D, texture_id);
+
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
+
+  gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, width, height, NULL);
+
+  if (min_filter != GL_NEAREST)
+    glGenerateMipmap (GL_TEXTURE_2D);
+
+  t.texture_id = texture_id;
+  t.width = width;
+  t.height = height;
+  g_array_append_val (driver->textures, t);
+
+  return texture_id;
+}
+
+int
+gsk_gl_driver_create_vao_for_quad (GskGLDriver   *driver,
+                                   int            position_id,
+                                   int            uv_id,
+                                   int            n_quads,
+                                   GskQuadVertex *quads)
+
+{
+  GLuint vao_id, buffer_id;
+  Vao v;
+
+  g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
+
+  glGenVertexArrays (1, &vao_id);
+  glBindVertexArray (vao_id);
+
+  glGenBuffers (1, &buffer_id);
+  glBindBuffer (GL_ARRAY_BUFFER, buffer_id);
+  glBufferData (GL_ARRAY_BUFFER, n_quads, quads, GL_STATIC_DRAW);
+
+  glEnableVertexAttribArray (position_id);
+  glVertexAttribPointer (position_id, 2, GL_FLOAT, GL_FALSE,
+                         sizeof (GskQuadVertex),
+                         (void *) G_STRUCT_OFFSET (GskQuadVertex, position));
+
+  glEnableVertexAttribArray (uv_id);
+  glVertexAttribPointer (uv_id, 2, GL_FLOAT, GL_FALSE,
+                         sizeof (GskQuadVertex),
+                         (void *) G_STRUCT_OFFSET (GskQuadVertex, uv));
+
+  glBindBuffer (GL_ARRAY_BUFFER, 0);
+  glBindVertexArray (0);
+
+  v.vao_id = vao_id;
+  v.buffer_id =  buffer_id;
+  v.position_id = position_id;
+  v.uv_id = uv_id;
+  g_array_append_val (driver->vaos, v);
+
+  return vao_id;
+}
+
+static Texture *
+gsk_gl_driver_get_texture (GskGLDriver *driver,
+                           int          texture_id)
+{
+  int i;
+
+  for (i = 0; i < driver->textures->len; i++)
+    {
+      Texture *t = &g_array_index (driver->textures, Texture, i);
+      if (t->texture_id == texture_id)
+        return t;
+    }
+
+  return NULL;
+}
+
+static Vao *
+gsk_gl_driver_get_vao (GskGLDriver *driver,
+                       int          vao_id)
+{
+  int i;
+
+  for (i = 0; i < driver->vaos->len; i++)
+    {
+      Vao *v = &g_array_index (driver->vaos, Vao, i);
+      if (v->vao_id == vao_id)
+        return v;
+    }
+
+  return NULL;
+}
+
+void
+gsk_gl_driver_bind_source_texture (GskGLDriver *driver,
+                                   int          texture_id)
+{
+  Texture *t;
+
+  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
+  g_return_if_fail (driver->in_frame);
+
+  t = gsk_gl_driver_get_texture (driver, texture_id);
+  if (t == NULL)
+    return;
+
+  if (driver->bound_source_texture != t)
+    {
+      glActiveTexture (GL_TEXTURE0);
+      glBindTexture (GL_TEXTURE_2D, t->texture_id);
+
+      driver->bound_source_texture = t;
+    }
+}
+
+void
+gsk_gl_driver_bind_mask_texture (GskGLDriver *driver,
+                                 int          texture_id)
+{
+  Texture *t;
+
+  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
+  g_return_if_fail (driver->in_frame);
+
+  t = gsk_gl_driver_get_texture (driver, texture_id);
+  if (t == NULL)
+    return;
+
+  if (driver->bound_mask_texture != t)
+    {
+      glActiveTexture (GL_TEXTURE0 + 1);
+      glBindTexture (GL_TEXTURE_2D, t->texture_id);
+
+      glActiveTexture (GL_TEXTURE0);
+
+      driver->bound_mask_texture = t;
+    }
+}
+
+void
+gsk_gl_driver_bind_vao (GskGLDriver *driver,
+                        int          vao_id)
+{
+  Vao *v;
+
+  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
+  g_return_if_fail (driver->in_frame);
+
+  v = gsk_gl_driver_get_vao (driver, vao_id);
+  if (v == NULL)
+    return;
+
+  if (driver->bound_vao != v)
+    {
+      glBindVertexArray (v->vao_id);
+      glBindBuffer (GL_ARRAY_BUFFER, v->buffer_id);
+      glEnableVertexAttribArray (v->position_id);
+      glEnableVertexAttribArray (v->uv_id);
+
+      driver->bound_vao = v;
+    }
+}
diff --git a/gsk/gskgldriverprivate.h b/gsk/gskgldriverprivate.h
new file mode 100644
index 0000000..53f97cd
--- /dev/null
+++ b/gsk/gskgldriverprivate.h
@@ -0,0 +1,45 @@
+#ifndef __GSK_GL_DRIVER_PRIVATE_H__
+#define __GSK_GL_DRIVER_PRIVATE_H__
+
+#include <cairo.h>
+#include <gdk/gdk.h>
+#include <graphene.h>
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskGLDriver, gsk_gl_driver, GSK, GL_DRIVER, GObject)
+
+typedef struct {
+  float position[2];
+  float uv[2];
+} GskQuadVertex;
+
+GskGLDriver *   gsk_gl_driver_new                       (GdkGLContext    *context);
+
+void            gsk_gl_driver_begin_frame               (GskGLDriver     *driver);
+void            gsk_gl_driver_end_frame                 (GskGLDriver     *driver);
+
+int             gsk_gl_driver_create_texture            (GskGLDriver     *driver,
+                                                         int              width,
+                                                         int              height,
+                                                         int              min_filter,
+                                                         int              mag_filter,
+                                                         cairo_surface_t *surface);
+int             gsk_gl_driver_create_vao_for_quad       (GskGLDriver     *driver,
+                                                         int              position_id,
+                                                         int              uv_id,
+                                                         int              n_vertices,
+                                                         GskQuadVertex   *vertices);
+
+void            gsk_gl_driver_bind_source_texture       (GskGLDriver     *driver,
+                                                         int              texture_id);
+void            gsk_gl_driver_bind_mask_texture         (GskGLDriver     *driver,
+                                                         int              texture_id);
+void            gsk_gl_driver_bind_vao                  (GskGLDriver     *driver,
+                                                         int              vao_id);
+
+G_END_DECLS
+
+#endif /* __GSK_GL_DRIVER_PRIVATE_H__ */
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index f0d4344..8291107 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -4,6 +4,7 @@
 
 #include "gskdebugprivate.h"
 #include "gskenums.h"
+#include "gskgldriverprivate.h"
 #include "gskrendererprivate.h"
 #include "gskrendernodeprivate.h"
 #include "gskrendernodeiter.h"
@@ -87,8 +88,13 @@ struct _GskGLRenderer
   GQuark uniforms[N_UNIFORMS];
   GQuark attributes[N_ATTRIBUTES];
 
+  GskGLDriver *gl_driver;
+
   GskShaderBuilder *shader_builder;
 
+  int gl_min_filter;
+  int gl_mag_filter;
+
   int blend_program_id;
   int blit_program_id;
 
@@ -108,8 +114,6 @@ struct _GskGLRendererClass
   GskRendererClass parent_class;
 };
 
-static void render_item_clear (gpointer data_);
-
 G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
 
 static void
@@ -415,6 +419,9 @@ gsk_gl_renderer_realize (GskRenderer *renderer)
 
   gdk_gl_context_make_current (self->context);
 
+  g_assert (self->gl_driver == NULL);
+  self->gl_driver = gsk_gl_driver_new (self->context);
+
   GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
   if (!gsk_gl_renderer_create_programs (self))
     return FALSE;
@@ -440,6 +447,8 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
   gsk_gl_renderer_destroy_buffers (self);
   gsk_gl_renderer_destroy_programs (self);
 
+  g_clear_object (&self->gl_driver);
+
   if (self->context == gdk_gl_context_get_current ())
     gdk_gl_context_clear_current ();
 }
@@ -471,97 +480,29 @@ gsk_gl_renderer_update_frustum (GskGLRenderer           *self,
   GSK_NOTE (OPENGL, graphene_matrix_print (&self->mvp));
 }
 
-static void
-render_item_clear (gpointer data_)
-{
-  RenderItem *item = data_;
-
-  GSK_NOTE (OPENGL, g_print ("Destroying render item [%p] buffer %u\n",
-                             item,
-                             item->render_data.buffer_id));
-  glDeleteBuffers (1, &item->render_data.buffer_id);
-  item->render_data.buffer_id = 0;
-
-  GSK_NOTE (OPENGL, g_print ("Destroying render item [%p] texture %u\n",
-                             item,
-                             item->render_data.texture_id));
-  glDeleteTextures (1, &item->render_data.texture_id);
-  item->render_data.texture_id = 0;
-
-  graphene_matrix_init_identity (&item->mvp);
-
-  item->opacity = 1;
-}
-
 #define N_VERTICES      6
 
 static void
-render_item (RenderItem *item)
+render_item (GskGLRenderer *self,
+             RenderItem    *item)
 {
-  struct vertex_info {
-    float position[2];
-    float uv[2];
-  };
   float mvp[16];
 
-  glBindVertexArray (item->render_data.vao_id);
-
-  /* Generate the vertex buffer for the texture quad */
-  if (item->render_data.buffer_id == 0)
-    {
-      struct vertex_info vertex_data[] = {
-        { { item->min.x, item->min.y }, { 0, 0 }, },
-        { { item->min.x, item->max.y }, { 0, 1 }, },
-        { { item->max.x, item->min.y }, { 1, 0 }, },
-
-        { { item->max.x, item->max.y }, { 1, 1 }, },
-        { { item->min.x, item->max.y }, { 0, 1 }, },
-        { { item->max.x, item->min.y }, { 1, 0 }, },
-      };
-
-      GSK_NOTE (OPENGL, g_print ("Creating quad for render item [%p]\n", item));
-
-      glGenBuffers (1, &(item->render_data.buffer_id));
-      glBindBuffer (GL_ARRAY_BUFFER, item->render_data.buffer_id);
-
-      /* The data won't change */
-      glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data, GL_STATIC_DRAW);
-  
-      /* Set up the buffers with the computed position and texels */
-      glEnableVertexAttribArray (item->render_data.position_location);
-      glVertexAttribPointer (item->render_data.position_location, 2, GL_FLOAT, GL_FALSE,
-                             sizeof (struct vertex_info),
-                             (void *) G_STRUCT_OFFSET (struct vertex_info, position));
-      glEnableVertexAttribArray (item->render_data.uv_location);
-      glVertexAttribPointer (item->render_data.uv_location, 2, GL_FLOAT, GL_FALSE,
-                             sizeof (struct vertex_info),
-                             (void *) G_STRUCT_OFFSET (struct vertex_info, uv));
-    }
-  else
-    {
-      /* We already set up the vertex buffer, so we just need to reuse it */
-      glBindBuffer (GL_ARRAY_BUFFER, item->render_data.buffer_id);
-      glEnableVertexAttribArray (item->render_data.position_location);
-      glEnableVertexAttribArray (item->render_data.uv_location);
-    }
+  gsk_gl_driver_bind_vao (self->gl_driver, item->render_data.vao_id);
 
   glUseProgram (item->render_data.program_id);
 
-  /* Use texture unit 0 for the sampler */
-  glActiveTexture (GL_TEXTURE0);
-  glBindTexture (GL_TEXTURE_2D, item->render_data.texture_id);
+  /* Use texture unit 0 for the source */
   glUniform1i (item->render_data.map_location, 0);
+  gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_data.texture_id);
 
   if (item->parent_data != NULL)
     {
-      if (item->parent_data->texture_id != 0)
-        {
-          glActiveTexture (GL_TEXTURE1);
-          glBindTexture (GL_TEXTURE_2D, item->parent_data->texture_id);
-          glUniform1i (item->render_data.parentMap_location, 1);
-        }
-
       glUniform1i (item->render_data.blendMode_location, item->blend_mode);
+
+      /* Use texture unit 1 for the mask */
+      if (item->parent_data->texture_id != 0)
+        gsk_gl_driver_bind_mask_texture (self->gl_driver, item->parent_data->texture_id);
     }
 
   /* Pass the opacity component */
@@ -579,45 +520,6 @@ render_item (RenderItem *item)
                              item->opaque ? 1 : item->opacity));
 
   glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
-
-  /* Reset the state */
-  glBindTexture (GL_TEXTURE_2D, 0);
-  glDisableVertexAttribArray (item->render_data.position_location);
-  glDisableVertexAttribArray (item->render_data.uv_location);
-  glUseProgram (0);
-}
-
-static void
-surface_to_texture (cairo_surface_t *surface,
-                    graphene_rect_t *clip,
-                    int              min_filter,
-                    int              mag_filter,
-                    guint           *texture_out)
-{
-  guint texture_id;
-
-  glGenTextures (1, &texture_id);
-  glBindTexture (GL_TEXTURE_2D, texture_id);
-
-  GSK_NOTE (OPENGL, g_print ("Uploading surface[%p] { w:%g, h:%g } to texid:%d\n",
-                             surface,
-                             clip->size.width,
-                             clip->size.height,
-                             texture_id));
-
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
-
-  gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, clip->size.width, clip->size.height, NULL);
-
-  if (min_filter != GL_NEAREST)
-    glGenerateMipmap (GL_TEXTURE_2D);
-
-  GSK_NOTE (OPENGL, g_print ("New texture id %d from surface %p\n", texture_id, surface));
-
-  *texture_out = texture_id;
 }
 
 static void
@@ -692,7 +594,6 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
                                  RenderItem    *parent)
 {
   graphene_rect_t viewport;
-  int gl_min_filter, gl_mag_filter;
   cairo_surface_t *surface;
   GskRenderNodeIter iter;
   graphene_matrix_t mv, projection;
@@ -742,9 +643,11 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
 
   item.blend_mode = gsk_render_node_get_blend_mode (node);
 
-  /* GL objects */
-  item.render_data.vao_id = self->vao_id;
-  item.render_data.buffer_id = 0;
+  /* Back-pointer to the parent node */
+  if (parent != NULL)
+    item.parent_data = &(parent->render_data);
+  else
+    item.parent_data = NULL;
 
   /* Select the program to use */
   if (parent != NULL)
@@ -752,6 +655,9 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
   else
     program_id = self->blit_program_id;
 
+  item.render_data.program_id = program_id;
+
+  /* Retrieve all the uniforms and attributes */
   item.render_data.map_location =
     gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MAP]);
   item.render_data.parentMap_location =
@@ -768,12 +674,25 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
   item.render_data.uv_location =
     gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[UV]);
 
-  item.render_data.program_id = program_id;
-
-  if (parent != NULL)
-    item.parent_data = &(parent->render_data);
-  else
-    item.parent_data = NULL;
+  /* Create the vertex buffers holding the geometry of the quad */
+  {
+    GskQuadVertex vertex_data[N_VERTICES] = {
+      { { item.min.x, item.min.y }, { 0, 0 }, },
+      { { item.min.x, item.max.y }, { 0, 1 }, },
+      { { item.max.x, item.min.y }, { 1, 0 }, },
+
+      { { item.max.x, item.max.y }, { 1, 1 }, },
+      { { item.min.x, item.max.y }, { 0, 1 }, },
+      { { item.max.x, item.min.y }, { 1, 0 }, },
+    };
+
+    item.render_data.vao_id =
+      gsk_gl_driver_create_vao_for_quad (self->gl_driver,
+                                         item.render_data.position_location,
+                                         item.render_data.uv_location,
+                                         sizeof (GskQuadVertex) * N_VERTICES,
+                                         vertex_data);
+  }
 
   gsk_renderer_get_projection (GSK_RENDERER (self), &projection);
   item.z = project_item (&projection, &mv);
@@ -784,7 +703,6 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
    * do a single upload; alternatively, we could use a separate FBO and
    * render each texture into it
    */
-  get_gl_scaling_filters (GSK_RENDERER (self), &gl_min_filter, &gl_mag_filter);
   surface = gsk_render_node_get_surface (node);
 
   /* If the node does not have any surface we skip drawing it, but we still
@@ -796,7 +714,13 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
   if (surface == NULL)
     goto recurse_children;
 
-  surface_to_texture (surface, &bounds, gl_min_filter, gl_mag_filter, &(item.render_data.texture_id));
+  /* Upload the Cairo surface to a GL texture */
+  item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+                                                              bounds.size.width,
+                                                              bounds.size.height,
+                                                              self->gl_min_filter,
+                                                              self->gl_mag_filter,
+                                                              surface);
 
   GSK_NOTE (OPENGL, g_print ("Adding node <%s>[%p] to render items\n",
                              node->name != NULL ? node->name : "unnamed",
@@ -841,9 +765,6 @@ gsk_gl_renderer_validate_tree (GskGLRenderer *self,
   self->opaque_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes);
   self->transparent_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes);
 
-  g_array_set_clear_func (self->opaque_render_items, render_item_clear);
-  g_array_set_clear_func (self->transparent_render_items, render_item_clear);
-
   GSK_NOTE (OPENGL, g_print ("RenderNode -> RenderItem\n"));
   gsk_gl_renderer_add_render_item (self, root, NULL);
 
@@ -904,10 +825,17 @@ gsk_gl_renderer_render (GskRenderer *renderer,
   gsk_gl_renderer_allocate_buffers (self, viewport.size.width, viewport.size.height);
   gsk_gl_renderer_attach_buffers (self);
 
-  if (self->has_depth_buffer)
-    glEnable (GL_DEPTH_TEST);
-  else
-    glDisable (GL_DEPTH_TEST);
+  gsk_renderer_get_modelview (renderer, &modelview);
+  gsk_renderer_get_projection (renderer, &projection);
+  gsk_gl_renderer_update_frustum (self, &modelview, &projection);
+
+  get_gl_scaling_filters (GSK_RENDERER (self),
+                          &self->gl_min_filter,
+                          &self->gl_mag_filter);
+  if (!gsk_gl_renderer_validate_tree (self, root))
+    goto out;
+
+  gsk_gl_driver_begin_frame (self->gl_driver);
 
   /* Ensure that the viewport is up to date */
   status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
@@ -916,12 +844,7 @@ gsk_gl_renderer_render (GskRenderer *renderer,
 
   gsk_gl_renderer_clear (self);
 
-  gsk_renderer_get_modelview (renderer, &modelview);
-  gsk_renderer_get_projection (renderer, &projection);
-  gsk_gl_renderer_update_frustum (self, &modelview, &projection);
-
-  if (!gsk_gl_renderer_validate_tree (self, root))
-    goto out;
+  glDisable (GL_BLEND);
 
   /* Opaque pass: front-to-back */
   GSK_NOTE (OPENGL, g_print ("Rendering %u opaque items\n", self->opaque_render_items->len));
@@ -929,10 +852,12 @@ gsk_gl_renderer_render (GskRenderer *renderer,
     {
       RenderItem *item = &g_array_index (self->opaque_render_items, RenderItem, i);
 
-      render_item (item);
+      render_item (self, item);
     }
 
   glEnable (GL_BLEND);
+  glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+  glBlendEquation (GL_FUNC_ADD);
 
   /* Transparent pass: back-to-front */
   GSK_NOTE (OPENGL, g_print ("Rendering %u transparent items\n", self->transparent_render_items->len));
@@ -940,11 +865,9 @@ gsk_gl_renderer_render (GskRenderer *renderer,
     {
       RenderItem *item = &g_array_index (self->transparent_render_items, RenderItem, i);
 
-      render_item (item);
+      render_item (self, item);
     }
 
-  glDisable (GL_BLEND);
-
   /* Draw the output of the GL rendering to the window */
   GSK_NOTE (OPENGL, g_print ("Drawing GL content on Cairo surface using a %s\n",
                              self->texture_id != 0 ? "texture" : "renderbuffer"));
@@ -960,7 +883,7 @@ out:
                           0, 0, viewport.size.width, viewport.size.height);
 
   gdk_gl_context_make_current (self->context);
-
+  gsk_gl_driver_end_frame (self->gl_driver);
   gsk_gl_renderer_clear_tree (self);
 }
 


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