mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 19:00:08 +00:00
gsk: Add GskGLDriver
We can move the caching and management of textures, VAOs, and state of the GL machinery into a single object, GskGLDriver.
This commit is contained in:
parent
8555c6ba11
commit
46bb14e173
@ -37,6 +37,7 @@ gsk_public_source_h = \
|
||||
gsk_private_source_h = \
|
||||
gskcairorendererprivate.h \
|
||||
gskdebugprivate.h \
|
||||
gskgldriverprivate.h \
|
||||
gskglrendererprivate.h \
|
||||
gskprivate.h \
|
||||
gskrendererprivate.h \
|
||||
@ -53,6 +54,7 @@ gsk_built_source_c = \
|
||||
gsk_source_c = \
|
||||
gskcairorenderer.c \
|
||||
gskdebug.c \
|
||||
gskgldriver.c \
|
||||
gskglrenderer.c \
|
||||
gskrenderer.c \
|
||||
gskrendernode.c \
|
||||
|
369
gsk/gskgldriver.c
Normal file
369
gsk/gskgldriver.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
45
gsk/gskgldriverprivate.h
Normal file
45
gsk/gskgldriverprivate.h
Normal file
@ -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__ */
|
@ -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;
|
||||
/* 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 }, },
|
||||
|
||||
if (parent != NULL)
|
||||
item.parent_data = &(parent->render_data);
|
||||
else
|
||||
item.parent_data = NULL;
|
||||
{ { 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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user