2016-07-08 15:21:13 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gskgldriverprivate.h"
|
|
|
|
|
|
|
|
#include "gskdebugprivate.h"
|
2017-11-02 20:39:00 +00:00
|
|
|
#include "gdk/gdktextureprivate.h"
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
#include <epoxy/gl.h>
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
GLuint texture_id;
|
|
|
|
int width;
|
|
|
|
int height;
|
2016-07-12 10:15:45 +00:00
|
|
|
GLuint min_filter;
|
|
|
|
GLuint mag_filter;
|
2016-07-12 14:41:31 +00:00
|
|
|
GArray *fbos;
|
2017-11-02 20:39:00 +00:00
|
|
|
GdkTexture *user;
|
2016-08-04 11:37:54 +00:00
|
|
|
gboolean in_use : 1;
|
2016-07-08 15:21:13 +00:00
|
|
|
} Texture;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
GLuint vao_id;
|
|
|
|
GLuint buffer_id;
|
|
|
|
GLuint position_id;
|
|
|
|
GLuint uv_id;
|
2016-08-09 10:24:05 +00:00
|
|
|
GskQuadVertex *quads;
|
|
|
|
int n_quads;
|
|
|
|
gboolean in_use : 1;
|
2016-07-08 15:21:13 +00:00
|
|
|
} Vao;
|
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
typedef struct {
|
|
|
|
GLuint fbo_id;
|
|
|
|
GLuint depth_stencil_id;
|
|
|
|
} Fbo;
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
struct _GskGLDriver
|
|
|
|
{
|
|
|
|
GObject parent_instance;
|
|
|
|
|
|
|
|
GdkGLContext *gl_context;
|
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
Fbo default_fbo;
|
2016-07-12 14:41:31 +00:00
|
|
|
|
2016-07-12 13:59:37 +00:00
|
|
|
GHashTable *textures;
|
2016-07-20 16:55:35 +00:00
|
|
|
GHashTable *vaos;
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
Texture *bound_source_texture;
|
|
|
|
Texture *bound_mask_texture;
|
|
|
|
Vao *bound_vao;
|
2016-07-20 16:55:35 +00:00
|
|
|
Fbo *bound_fbo;
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-10-26 14:47:29 +00:00
|
|
|
int max_texture_size;
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
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)
|
|
|
|
|
2016-07-12 13:59:37 +00:00
|
|
|
static Texture *
|
|
|
|
texture_new (void)
|
|
|
|
{
|
|
|
|
return g_slice_new0 (Texture);
|
|
|
|
}
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
static void
|
2016-07-12 13:59:37 +00:00
|
|
|
texture_free (gpointer data)
|
2016-07-08 15:21:13 +00:00
|
|
|
{
|
|
|
|
Texture *t = data;
|
|
|
|
|
2016-11-16 04:37:20 +00:00
|
|
|
if (t->user)
|
2017-11-02 20:39:00 +00:00
|
|
|
gdk_texture_clear_render_data (t->user);
|
2016-11-07 16:59:38 +00:00
|
|
|
|
2016-07-12 14:41:31 +00:00
|
|
|
g_clear_pointer (&t->fbos, g_array_unref);
|
2016-07-08 15:21:13 +00:00
|
|
|
glDeleteTextures (1, &t->texture_id);
|
2016-07-12 13:59:37 +00:00
|
|
|
g_slice_free (Texture, t);
|
2016-07-08 15:21:13 +00:00
|
|
|
}
|
|
|
|
|
2016-07-12 14:41:31 +00:00
|
|
|
static void
|
|
|
|
fbo_clear (gpointer data)
|
|
|
|
{
|
2016-07-20 16:55:35 +00:00
|
|
|
Fbo *f = data;
|
|
|
|
|
|
|
|
if (f->depth_stencil_id != 0)
|
|
|
|
glDeleteRenderbuffers (1, &f->depth_stencil_id);
|
|
|
|
|
|
|
|
glDeleteFramebuffers (1, &f->fbo_id);
|
|
|
|
}
|
2016-07-12 14:41:31 +00:00
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
static Vao *
|
|
|
|
vao_new (void)
|
|
|
|
{
|
|
|
|
return g_slice_new0 (Vao);
|
2016-07-12 14:41:31 +00:00
|
|
|
}
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
static void
|
2016-07-20 16:55:35 +00:00
|
|
|
vao_free (gpointer data)
|
2016-07-08 15:21:13 +00:00
|
|
|
{
|
|
|
|
Vao *v = data;
|
|
|
|
|
2016-08-09 10:24:05 +00:00
|
|
|
g_free (v->quads);
|
2016-07-08 15:21:13 +00:00
|
|
|
glDeleteBuffers (1, &v->buffer_id);
|
|
|
|
glDeleteVertexArrays (1, &v->vao_id);
|
2016-07-20 16:55:35 +00:00
|
|
|
g_slice_free (Vao, v);
|
2016-07-08 15:21:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gsk_gl_driver_finalize (GObject *gobject)
|
|
|
|
{
|
|
|
|
GskGLDriver *self = GSK_GL_DRIVER (gobject);
|
|
|
|
|
2016-08-04 11:37:54 +00:00
|
|
|
gdk_gl_context_make_current (self->gl_context);
|
|
|
|
|
2016-07-12 13:59:37 +00:00
|
|
|
g_clear_pointer (&self->textures, g_hash_table_unref);
|
2016-07-20 16:55:35 +00:00
|
|
|
g_clear_pointer (&self->vaos, g_hash_table_unref);
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-08-04 11:37:54 +00:00
|
|
|
if (self->gl_context == gdk_gl_context_get_current ())
|
|
|
|
gdk_gl_context_clear_current ();
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
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)
|
|
|
|
{
|
2016-07-12 13:59:37 +00:00
|
|
|
self->textures = g_hash_table_new_full (NULL, NULL, NULL, texture_free);
|
2016-07-20 16:55:35 +00:00
|
|
|
self->vaos = g_hash_table_new_full (NULL, NULL, NULL, vao_free);
|
2016-10-26 14:47:29 +00:00
|
|
|
|
|
|
|
self->max_texture_size = -1;
|
2016-07-08 15:21:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2016-10-26 14:47:29 +00:00
|
|
|
if (driver->max_texture_size < 0)
|
|
|
|
{
|
|
|
|
glGetIntegerv (GL_MAX_TEXTURE_SIZE, (GLint *) &driver->max_texture_size);
|
|
|
|
GSK_NOTE (OPENGL, g_print ("GL max texture size: %d\n", driver->max_texture_size));
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:03:59 +00:00
|
|
|
glBindFramebuffer (GL_FRAMEBUFFER, 0);
|
2016-07-20 16:55:35 +00:00
|
|
|
driver->bound_fbo = &driver->default_fbo;
|
2016-07-12 14:41:31 +00:00
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
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;
|
2016-07-20 16:55:35 +00:00
|
|
|
driver->bound_fbo = NULL;
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-11-23 00:03:59 +00:00
|
|
|
driver->default_fbo.fbo_id = 0;
|
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
GSK_NOTE (OPENGL,
|
|
|
|
g_print ("*** Frame end: textures=%d, vaos=%d\n",
|
|
|
|
g_hash_table_size (driver->textures),
|
|
|
|
g_hash_table_size (driver->vaos)));
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
driver->in_frame = FALSE;
|
|
|
|
}
|
|
|
|
|
2016-08-09 10:24:05 +00:00
|
|
|
int
|
2016-08-04 11:37:54 +00:00
|
|
|
gsk_gl_driver_collect_textures (GskGLDriver *driver)
|
|
|
|
{
|
|
|
|
GHashTableIter iter;
|
|
|
|
gpointer value_p = NULL;
|
2016-08-09 10:24:05 +00:00
|
|
|
int old_size;
|
2016-08-04 11:37:54 +00:00
|
|
|
|
2016-08-09 10:24:05 +00:00
|
|
|
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
|
|
|
|
g_return_val_if_fail (!driver->in_frame, 0);
|
|
|
|
|
|
|
|
old_size = g_hash_table_size (driver->textures);
|
2016-08-04 11:37:54 +00:00
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, driver->textures);
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
|
|
|
{
|
|
|
|
Texture *t = value_p;
|
|
|
|
|
2016-11-16 04:37:20 +00:00
|
|
|
if (t->user)
|
2016-11-07 16:59:38 +00:00
|
|
|
continue;
|
|
|
|
|
2016-08-04 11:37:54 +00:00
|
|
|
if (t->in_use)
|
2016-08-09 10:24:05 +00:00
|
|
|
{
|
|
|
|
t->in_use = FALSE;
|
|
|
|
g_clear_pointer (&t->fbos, g_array_unref);
|
|
|
|
}
|
2016-08-04 11:37:54 +00:00
|
|
|
else
|
|
|
|
g_hash_table_iter_remove (&iter);
|
|
|
|
}
|
2016-08-09 10:24:05 +00:00
|
|
|
|
|
|
|
return old_size - g_hash_table_size (driver->textures);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
gsk_gl_driver_collect_vaos (GskGLDriver *driver)
|
|
|
|
{
|
|
|
|
GHashTableIter iter;
|
|
|
|
gpointer value_p = NULL;
|
|
|
|
int old_size;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
|
|
|
|
g_return_val_if_fail (!driver->in_frame, 0);
|
|
|
|
|
|
|
|
old_size = g_hash_table_size (driver->vaos);
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, driver->vaos);
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
|
|
|
{
|
|
|
|
Vao *v = value_p;
|
|
|
|
|
|
|
|
if (v->in_use)
|
|
|
|
v->in_use = FALSE;
|
|
|
|
else
|
|
|
|
g_hash_table_iter_remove (&iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
return old_size - g_hash_table_size (driver->vaos);
|
2016-08-04 11:37:54 +00:00
|
|
|
}
|
|
|
|
|
2016-10-26 14:47:29 +00:00
|
|
|
int
|
|
|
|
gsk_gl_driver_get_max_texture_size (GskGLDriver *driver)
|
|
|
|
{
|
|
|
|
if (driver->max_texture_size < 0)
|
|
|
|
{
|
|
|
|
if (gdk_gl_context_get_use_es (driver->gl_context))
|
|
|
|
return 2048;
|
|
|
|
|
|
|
|
return 1024;
|
|
|
|
}
|
|
|
|
|
|
|
|
return driver->max_texture_size;
|
|
|
|
}
|
|
|
|
|
2016-07-12 14:41:31 +00:00
|
|
|
static Texture *
|
|
|
|
gsk_gl_driver_get_texture (GskGLDriver *driver,
|
|
|
|
int texture_id)
|
|
|
|
{
|
2016-07-20 16:55:35 +00:00
|
|
|
Texture *t;
|
|
|
|
|
|
|
|
if (g_hash_table_lookup_extended (driver->textures, GINT_TO_POINTER (texture_id), NULL, (gpointer *) &t))
|
|
|
|
return t;
|
|
|
|
|
|
|
|
return NULL;
|
2016-07-12 14:41:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static Vao *
|
|
|
|
gsk_gl_driver_get_vao (GskGLDriver *driver,
|
|
|
|
int vao_id)
|
|
|
|
{
|
2016-07-20 16:55:35 +00:00
|
|
|
Vao *v;
|
2016-07-12 14:41:31 +00:00
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
if (g_hash_table_lookup_extended (driver->vaos, GINT_TO_POINTER (vao_id), NULL, (gpointer *) &v))
|
|
|
|
return v;
|
2016-07-12 14:41:31 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
static Fbo *
|
|
|
|
gsk_gl_driver_get_fbo (GskGLDriver *driver,
|
|
|
|
int texture_id)
|
|
|
|
{
|
|
|
|
Texture *t = gsk_gl_driver_get_texture (driver, texture_id);
|
|
|
|
|
|
|
|
if (t->fbos == NULL)
|
|
|
|
return &driver->default_fbo;
|
|
|
|
|
|
|
|
return &g_array_index (t->fbos, Fbo, 0);
|
|
|
|
}
|
|
|
|
|
2016-08-04 11:37:54 +00:00
|
|
|
static Texture *
|
|
|
|
find_texture_by_size (GHashTable *textures,
|
|
|
|
int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
GHashTableIter iter;
|
|
|
|
gpointer value_p = NULL;
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, textures);
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
|
|
|
{
|
|
|
|
Texture *t = value_p;
|
|
|
|
|
|
|
|
if (t->width == width && t->height == height)
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-16 04:37:20 +00:00
|
|
|
static Texture *
|
|
|
|
create_texture (GskGLDriver *driver,
|
|
|
|
int width,
|
|
|
|
int height)
|
2016-07-08 15:21:13 +00:00
|
|
|
{
|
|
|
|
guint texture_id;
|
2016-07-12 13:59:37 +00:00
|
|
|
Texture *t;
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-10-26 14:47:29 +00:00
|
|
|
if (width >= driver->max_texture_size ||
|
|
|
|
height >= driver->max_texture_size)
|
|
|
|
{
|
|
|
|
g_critical ("Texture %d x %d is bigger than supported texture limit of %d; clipping...",
|
|
|
|
width, height,
|
|
|
|
driver->max_texture_size);
|
|
|
|
|
|
|
|
width = MIN (width, driver->max_texture_size);
|
|
|
|
height = MIN (height, driver->max_texture_size);
|
|
|
|
}
|
|
|
|
|
2016-08-04 11:37:54 +00:00
|
|
|
t = find_texture_by_size (driver->textures, width, height);
|
2016-11-16 04:37:20 +00:00
|
|
|
if (t != NULL && !t->in_use && t->user == NULL)
|
2016-08-04 11:37:54 +00:00
|
|
|
{
|
2016-08-09 10:24:05 +00:00
|
|
|
GSK_NOTE (OPENGL, g_print ("Reusing Texture(%d) for size %dx%d\n",
|
|
|
|
t->texture_id, t->width, t->height));
|
2016-08-04 11:37:54 +00:00
|
|
|
t->in_use = TRUE;
|
2016-11-16 04:37:20 +00:00
|
|
|
return t;
|
2016-08-04 11:37:54 +00:00
|
|
|
}
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
glGenTextures (1, &texture_id);
|
|
|
|
|
2016-07-12 13:59:37 +00:00
|
|
|
t = texture_new ();
|
|
|
|
t->texture_id = texture_id;
|
|
|
|
t->width = width;
|
|
|
|
t->height = height;
|
2016-07-19 13:32:17 +00:00
|
|
|
t->min_filter = GL_NEAREST;
|
|
|
|
t->mag_filter = GL_NEAREST;
|
2016-08-04 11:37:54 +00:00
|
|
|
t->in_use = TRUE;
|
2016-07-20 16:55:35 +00:00
|
|
|
g_hash_table_insert (driver->textures, GINT_TO_POINTER (texture_id), t);
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-11-16 04:37:20 +00:00
|
|
|
return t;
|
2016-07-08 15:21:13 +00:00
|
|
|
}
|
|
|
|
|
2016-11-16 04:37:20 +00:00
|
|
|
static void
|
|
|
|
gsk_gl_driver_release_texture (gpointer data)
|
|
|
|
{
|
|
|
|
Texture *t = data;
|
|
|
|
|
|
|
|
t->user = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver,
|
2017-11-02 20:39:00 +00:00
|
|
|
GdkTexture *texture,
|
2016-11-16 04:37:20 +00:00
|
|
|
int min_filter,
|
|
|
|
int mag_filter)
|
2016-11-07 16:59:38 +00:00
|
|
|
{
|
|
|
|
Texture *t;
|
2016-11-16 04:37:20 +00:00
|
|
|
cairo_surface_t *surface;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
|
2017-11-02 20:39:00 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_TEXTURE (texture), -1);
|
2016-11-16 04:37:20 +00:00
|
|
|
|
2017-11-02 20:39:00 +00:00
|
|
|
t = gdk_texture_get_render_data (texture, driver);
|
2016-11-16 04:37:20 +00:00
|
|
|
|
|
|
|
if (t)
|
|
|
|
{
|
|
|
|
if (t->min_filter == min_filter && t->mag_filter == mag_filter)
|
|
|
|
return t->texture_id;
|
|
|
|
}
|
2016-11-07 16:59:38 +00:00
|
|
|
|
2017-11-02 20:39:00 +00:00
|
|
|
t = create_texture (driver, gdk_texture_get_width (texture), gdk_texture_get_height (texture));
|
2016-11-16 04:37:20 +00:00
|
|
|
|
2017-11-02 20:39:00 +00:00
|
|
|
if (gdk_texture_set_render_data (texture, driver, t, gsk_gl_driver_release_texture))
|
2016-11-16 04:37:20 +00:00
|
|
|
t->user = texture;
|
|
|
|
|
2017-11-02 20:39:00 +00:00
|
|
|
surface = gdk_texture_download_surface (texture);
|
2016-11-16 04:37:20 +00:00
|
|
|
gsk_gl_driver_bind_source_texture (driver, t->texture_id);
|
|
|
|
gsk_gl_driver_init_texture_with_surface (driver,
|
|
|
|
t->texture_id,
|
|
|
|
surface,
|
|
|
|
min_filter,
|
|
|
|
mag_filter);
|
2016-11-18 01:29:07 +00:00
|
|
|
cairo_surface_destroy (surface);
|
2016-11-16 04:37:20 +00:00
|
|
|
|
|
|
|
return t->texture_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
gsk_gl_driver_create_texture (GskGLDriver *driver,
|
|
|
|
int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
Texture *t;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
|
2016-11-07 16:59:38 +00:00
|
|
|
|
2016-11-16 04:37:20 +00:00
|
|
|
t = create_texture (driver, width, height);
|
|
|
|
|
|
|
|
return t->texture_id;
|
2016-11-07 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-08-09 10:24:05 +00:00
|
|
|
static Vao *
|
|
|
|
find_vao (GHashTable *vaos,
|
|
|
|
int position_id,
|
|
|
|
int uv_id,
|
|
|
|
int n_quads,
|
|
|
|
GskQuadVertex *quads)
|
|
|
|
{
|
|
|
|
GHashTableIter iter;
|
|
|
|
gpointer value_p = NULL;
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, vaos);
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
|
|
|
{
|
|
|
|
Vao *v = value_p;
|
|
|
|
|
|
|
|
if (v->position_id != position_id || v->uv_id != uv_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (v->n_quads != n_quads)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (memcmp (v->quads, quads, sizeof (GskQuadVertex) * n_quads) == 0)
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
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;
|
2016-07-20 16:55:35 +00:00
|
|
|
Vao *v;
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
|
2016-07-20 16:55:35 +00:00
|
|
|
g_return_val_if_fail (driver->in_frame, -1);
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-08-09 10:24:05 +00:00
|
|
|
v = find_vao (driver->vaos, position_id, uv_id, n_quads, quads);
|
|
|
|
if (v != NULL && !v->in_use)
|
|
|
|
{
|
|
|
|
GSK_NOTE (OPENGL, g_print ("Reusing VAO(%d)\n", v->vao_id));
|
|
|
|
v->in_use = TRUE;
|
|
|
|
return v->vao_id;
|
|
|
|
}
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
glGenVertexArrays (1, &vao_id);
|
|
|
|
glBindVertexArray (vao_id);
|
|
|
|
|
|
|
|
glGenBuffers (1, &buffer_id);
|
|
|
|
glBindBuffer (GL_ARRAY_BUFFER, buffer_id);
|
2016-08-04 18:14:51 +00:00
|
|
|
glBufferData (GL_ARRAY_BUFFER, sizeof (GskQuadVertex) * n_quads, quads, GL_STATIC_DRAW);
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
v = vao_new ();
|
|
|
|
v->vao_id = vao_id;
|
|
|
|
v->buffer_id = buffer_id;
|
|
|
|
v->position_id = position_id;
|
|
|
|
v->uv_id = uv_id;
|
2016-08-09 10:24:05 +00:00
|
|
|
v->n_quads = n_quads;
|
|
|
|
v->quads = g_memdup (quads, sizeof (GskQuadVertex) * n_quads);
|
|
|
|
v->in_use = TRUE;
|
2016-07-20 16:55:35 +00:00
|
|
|
g_hash_table_insert (driver->vaos, GINT_TO_POINTER (vao_id), v);
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-08-04 18:14:51 +00:00
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
|
|
if (GSK_DEBUG_CHECK (OPENGL))
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
g_print ("New VAO(%d) for quad[%d] : {\n", v->vao_id, n_quads);
|
|
|
|
for (i = 0; i < n_quads; i++)
|
|
|
|
{
|
|
|
|
g_print (" { x:%.2f, y:%.2f } { u:%.2f, v:%.2f }\n",
|
|
|
|
quads[i].position[0], quads[i].position[1],
|
|
|
|
quads[i].uv[0], quads[i].uv[1]);
|
|
|
|
}
|
|
|
|
g_print ("}\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-07-08 15:21:13 +00:00
|
|
|
return vao_id;
|
|
|
|
}
|
|
|
|
|
2016-07-12 14:41:31 +00:00
|
|
|
int
|
|
|
|
gsk_gl_driver_create_render_target (GskGLDriver *driver,
|
2016-07-20 16:55:35 +00:00
|
|
|
int texture_id,
|
|
|
|
gboolean add_depth_buffer,
|
|
|
|
gboolean add_stencil_buffer)
|
2016-07-08 15:21:13 +00:00
|
|
|
{
|
2016-07-20 16:55:35 +00:00
|
|
|
GLuint fbo_id, depth_stencil_buffer_id;
|
2016-07-12 14:41:31 +00:00
|
|
|
Texture *t;
|
2016-07-20 16:55:35 +00:00
|
|
|
Fbo f;
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-07-12 14:41:31 +00:00
|
|
|
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
|
2016-07-20 16:55:35 +00:00
|
|
|
g_return_val_if_fail (driver->in_frame, -1);
|
2016-07-08 15:21:13 +00:00
|
|
|
|
2016-07-12 14:41:31 +00:00
|
|
|
t = gsk_gl_driver_get_texture (driver, texture_id);
|
|
|
|
if (t == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (t->fbos == NULL)
|
2016-07-08 15:21:13 +00:00
|
|
|
{
|
2016-07-20 16:55:35 +00:00
|
|
|
t->fbos = g_array_new (FALSE, FALSE, sizeof (Fbo));
|
2016-07-12 14:41:31 +00:00
|
|
|
g_array_set_clear_func (t->fbos, fbo_clear);
|
2016-07-08 15:21:13 +00:00
|
|
|
}
|
|
|
|
|
2016-07-12 14:41:31 +00:00
|
|
|
glGenFramebuffers (1, &fbo_id);
|
|
|
|
glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
|
|
|
|
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, t->texture_id, 0);
|
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
if (add_depth_buffer || add_stencil_buffer)
|
|
|
|
glGenRenderbuffersEXT (1, &depth_stencil_buffer_id);
|
|
|
|
else
|
|
|
|
depth_stencil_buffer_id = 0;
|
|
|
|
|
|
|
|
glBindRenderbuffer (GL_RENDERBUFFER, depth_stencil_buffer_id);
|
|
|
|
|
|
|
|
if (add_depth_buffer || add_stencil_buffer)
|
|
|
|
{
|
|
|
|
if (add_stencil_buffer)
|
|
|
|
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, t->width, t->height);
|
|
|
|
else
|
|
|
|
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, t->width, t->height);
|
|
|
|
|
|
|
|
if (add_depth_buffer)
|
|
|
|
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
|
|
|
GL_RENDERBUFFER, depth_stencil_buffer_id);
|
|
|
|
|
|
|
|
if (add_stencil_buffer)
|
|
|
|
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
|
|
|
GL_RENDERBUFFER, depth_stencil_buffer_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
f.fbo_id = fbo_id;
|
|
|
|
f.depth_stencil_id = depth_stencil_buffer_id;
|
2016-07-12 14:41:31 +00:00
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
g_array_append_val (t->fbos, f);
|
|
|
|
|
|
|
|
glBindFramebuffer (GL_FRAMEBUFFER, driver->default_fbo.fbo_id);
|
2016-07-12 14:41:31 +00:00
|
|
|
|
|
|
|
return fbo_id;
|
2016-07-08 15:21:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2016-07-20 16:55:35 +00:00
|
|
|
{
|
|
|
|
g_critical ("No texture %d found.", texture_id);
|
|
|
|
return;
|
|
|
|
}
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
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)
|
2016-07-20 16:55:35 +00:00
|
|
|
{
|
|
|
|
g_critical ("No texture %d found.", texture_id);
|
|
|
|
return;
|
|
|
|
}
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
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)
|
2016-07-20 16:55:35 +00:00
|
|
|
{
|
|
|
|
g_critical ("No VAO %d found.", vao_id);
|
|
|
|
return;
|
|
|
|
}
|
2016-07-08 15:21:13 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2016-07-12 10:15:45 +00:00
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
gboolean
|
2016-07-12 14:41:31 +00:00
|
|
|
gsk_gl_driver_bind_render_target (GskGLDriver *driver,
|
|
|
|
int texture_id)
|
|
|
|
{
|
2016-07-20 16:55:35 +00:00
|
|
|
int status;
|
|
|
|
Fbo *f;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), FALSE);
|
|
|
|
g_return_val_if_fail (driver->in_frame, FALSE);
|
|
|
|
|
2016-11-23 00:03:59 +00:00
|
|
|
if (texture_id == 0)
|
|
|
|
{
|
|
|
|
glBindFramebuffer (GL_FRAMEBUFFER, 0);
|
|
|
|
driver->bound_fbo = &driver->default_fbo;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
f = gsk_gl_driver_get_fbo (driver, texture_id);
|
|
|
|
if (f == NULL)
|
|
|
|
{
|
|
|
|
g_critical ("No render target associated to texture %d found.", texture_id);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f != driver->bound_fbo)
|
|
|
|
{
|
|
|
|
glBindFramebuffer (GL_FRAMEBUFFER, f->fbo_id);
|
|
|
|
|
|
|
|
driver->bound_fbo = f;
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:03:59 +00:00
|
|
|
out:
|
2016-07-20 16:55:35 +00:00
|
|
|
status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
|
|
|
|
|
|
|
|
return status == GL_FRAMEBUFFER_COMPLETE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gsk_gl_driver_destroy_texture (GskGLDriver *driver,
|
|
|
|
int texture_id)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
|
|
|
|
|
|
|
g_hash_table_remove (driver->textures, GINT_TO_POINTER (texture_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gsk_gl_driver_destroy_vao (GskGLDriver *driver,
|
|
|
|
int vao_id)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
|
|
|
|
|
|
|
g_hash_table_remove (driver->vaos, GINT_TO_POINTER (vao_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gsk_gl_driver_set_texture_parameters (GskGLDriver *driver,
|
|
|
|
int min_filter,
|
|
|
|
int mag_filter)
|
|
|
|
{
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
|
|
|
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gsk_gl_driver_init_texture_empty (GskGLDriver *driver,
|
|
|
|
int texture_id)
|
|
|
|
{
|
2016-07-12 14:41:31 +00:00
|
|
|
Texture *t;
|
|
|
|
|
|
|
|
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
|
|
|
|
|
|
|
t = gsk_gl_driver_get_texture (driver, texture_id);
|
|
|
|
if (t == NULL)
|
|
|
|
{
|
2016-07-20 16:55:35 +00:00
|
|
|
g_critical ("No texture %d found.", texture_id);
|
|
|
|
return;
|
|
|
|
}
|
2016-07-12 14:41:31 +00:00
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
if (!(driver->bound_source_texture == t || driver->bound_mask_texture == t))
|
|
|
|
{
|
|
|
|
g_critical ("You must bind the texture before initializing it.");
|
|
|
|
return;
|
2016-07-12 14:41:31 +00:00
|
|
|
}
|
2016-07-20 16:55:35 +00:00
|
|
|
|
|
|
|
gsk_gl_driver_set_texture_parameters (driver, t->min_filter, t->mag_filter);
|
|
|
|
|
|
|
|
if (gdk_gl_context_get_use_es (driver->gl_context))
|
|
|
|
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
else
|
|
|
|
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
|
|
|
|
glBindTexture (GL_TEXTURE_2D, 0);
|
2016-07-12 14:41:31 +00:00
|
|
|
}
|
|
|
|
|
2016-07-12 10:15:45 +00:00
|
|
|
void
|
2016-07-19 13:32:17 +00:00
|
|
|
gsk_gl_driver_init_texture_with_surface (GskGLDriver *driver,
|
|
|
|
int texture_id,
|
2016-07-12 10:15:45 +00:00
|
|
|
cairo_surface_t *surface,
|
2016-07-19 13:32:17 +00:00
|
|
|
int min_filter,
|
|
|
|
int mag_filter)
|
2016-07-12 10:15:45 +00:00
|
|
|
{
|
|
|
|
Texture *t;
|
|
|
|
|
|
|
|
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
|
|
|
|
|
|
|
t = gsk_gl_driver_get_texture (driver, texture_id);
|
|
|
|
if (t == NULL)
|
2016-07-20 16:55:35 +00:00
|
|
|
{
|
|
|
|
g_critical ("No texture %d found.", texture_id);
|
|
|
|
return;
|
|
|
|
}
|
2016-07-12 10:15:45 +00:00
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
if (!(driver->bound_source_texture == t || driver->bound_mask_texture == t))
|
|
|
|
{
|
|
|
|
g_critical ("You must bind the texture before initializing it.");
|
|
|
|
return;
|
|
|
|
}
|
2016-07-19 13:32:17 +00:00
|
|
|
|
2016-07-20 16:55:35 +00:00
|
|
|
gsk_gl_driver_set_texture_parameters (driver, min_filter, mag_filter);
|
2016-07-19 13:32:17 +00:00
|
|
|
|
2016-07-12 10:15:45 +00:00
|
|
|
gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, t->width, t->height, NULL);
|
|
|
|
|
2016-07-19 13:32:17 +00:00
|
|
|
t->min_filter = min_filter;
|
|
|
|
t->mag_filter = mag_filter;
|
|
|
|
|
2016-07-12 10:15:45 +00:00
|
|
|
if (t->min_filter != GL_NEAREST)
|
|
|
|
glGenerateMipmap (GL_TEXTURE_2D);
|
2016-07-20 16:55:35 +00:00
|
|
|
|
|
|
|
glBindTexture (GL_TEXTURE_2D, 0);
|
2016-07-12 10:15:45 +00:00
|
|
|
}
|