gsk: Consolidate program creation and storage

We should use ShaderBuilder to create and store programs for the GL
renderer. This allows us to simplify the creation of programs (by moving
the compilation phase into the ShaderBuilder::create_program() method),
and move towards the ability to create multiple programs and just keep a
reference to the program id.
This commit is contained in:
Emmanuele Bassi 2016-07-04 13:46:22 +01:00
parent 43974761bb
commit 4cda720ab9
3 changed files with 157 additions and 114 deletions

View File

@ -87,7 +87,9 @@ struct _GskGLRenderer
GQuark uniforms[N_UNIFORMS];
GQuark attributes[N_ATTRIBUTES];
GskShaderBuilder *blend_program;
GskShaderBuilder *shader_builder;
int blend_program_id;
guint vao_id;
@ -295,9 +297,6 @@ static gboolean
gsk_gl_renderer_create_programs (GskGLRenderer *self)
{
GskShaderBuilder *builder;
const char *vertex_preamble;
const char *fragment_preamble;
int vertex_id = -1, fragment_id = -1;
GError *error = NULL;
gboolean res = FALSE;
@ -317,26 +316,23 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self)
if (gdk_gl_context_get_use_es (self->context))
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES);
gsk_shader_builder_set_vertex_preamble (builder, "es2_common.vs.glsl");
gsk_shader_builder_set_fragment_preamble (builder, "es2_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_GLES", "1");
vertex_preamble = "gles_common.vs.glsl";
fragment_preamble = "gles_common.fs.glsl";
}
else if (gdk_gl_context_is_legacy (self->context))
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY);
gsk_shader_builder_set_vertex_preamble (builder, "gl_common.vs.glsl");
gsk_shader_builder_set_fragment_preamble (builder, "gl_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1");
vertex_preamble = "gl_common.vs.glsl";
fragment_preamble = "gl_common.fs.glsl";
}
else
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3);
gsk_shader_builder_set_vertex_preamble (builder, "gl3_common.vs.glsl");
gsk_shader_builder_set_fragment_preamble (builder, "gl3_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_GL3", "1");
vertex_preamble = "gl3_common.vs.glsl";
fragment_preamble = "gl3_common.fs.glsl";
}
#ifdef G_ENABLE_DEBUG
@ -344,62 +340,28 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self)
gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
#endif
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
vertex_preamble,
"blend.vs.glsl",
&error);
if (error != NULL)
{
g_critical ("Unable to compile vertex shader: %s", error->message);
g_error_free (error);
goto out;
}
fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
fragment_preamble,
"blend.fs.glsl",
&error);
if (error != NULL)
{
g_critical ("Unable to compile fragment shader: %s", error->message);
g_error_free (error);
goto out;
}
gsk_shader_builder_create_program (builder, vertex_id, fragment_id, &error);
self->blend_program_id =
gsk_shader_builder_create_program (builder, "blend.vs.glsl", "blend.fs.glsl", &error);
if (error != NULL)
{
g_critical ("Unable to create program: %s", error->message);
g_error_free (error);
g_object_unref (builder);
goto out;
}
self->blend_program = g_object_ref (builder);
self->shader_builder = builder;
res = TRUE;
out:
g_object_unref (builder);
if (vertex_id > 0)
glDeleteShader (vertex_id);
if (fragment_id > 0)
glDeleteShader (fragment_id);
return res;
}
static void
gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
{
if (self->blend_program != NULL)
{
int program_id = gsk_shader_builder_get_program (self->blend_program);
glDeleteProgram (program_id);
g_clear_object (&self->blend_program);
}
g_clear_object (&self->shader_builder);
}
static gboolean
@ -440,10 +402,11 @@ gsk_gl_renderer_realize (GskRenderer *renderer)
gdk_gl_context_make_current (self->context);
GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
gsk_gl_renderer_create_buffers (self);
if (!gsk_gl_renderer_create_programs (self))
return FALSE;
gsk_gl_renderer_create_buffers (self);
return TRUE;
}
@ -722,6 +685,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
graphene_rect_t bounds;
GskRenderNode *child;
RenderItem item;
int program_id;
if (gsk_render_node_is_hidden (node))
{
@ -767,23 +731,24 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
item.render_data.vao_id = self->vao_id;
item.render_data.buffer_id = 0;
item.render_data.program_id = gsk_shader_builder_get_program (self->blend_program);
program_id = self->blend_program_id;
item.render_data.program_id = program_id;
item.render_data.map_location =
gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MAP]);
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MAP]);
item.render_data.parentMap_location =
gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[PARENT_MAP]);
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[PARENT_MAP]);
item.render_data.mvp_location =
gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MVP]);
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MVP]);
item.render_data.alpha_location =
gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[ALPHA]);
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[ALPHA]);
item.render_data.blendMode_location =
gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[BLEND_MODE]);
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[BLEND_MODE]);
item.render_data.position_location =
gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[POSITION]);
gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[POSITION]);
item.render_data.uv_location =
gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[UV]);
gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[UV]);
if (parent != NULL)
item.parent_data = &(parent->render_data);

View File

@ -7,26 +7,58 @@
#include <gdk/gdk.h>
#include <epoxy/gl.h>
typedef struct {
int program_id;
GHashTable *uniform_locations;
GHashTable *attribute_locations;
} ShaderProgram;
struct _GskShaderBuilder
{
GObject parent_instance;
char *resource_base_path;
char *vertex_preamble;
char *fragment_preamble;
int version;
int program_id;
GPtrArray *defines;
GPtrArray *uniforms;
GPtrArray *attributes;
GHashTable *uniform_locations;
GHashTable *attribute_locations;
GHashTable *programs;
};
G_DEFINE_TYPE (GskShaderBuilder, gsk_shader_builder, G_TYPE_OBJECT)
static void
shader_program_free (gpointer data)
{
ShaderProgram *p = data;
g_clear_pointer (&p->uniform_locations, g_hash_table_unref);
g_clear_pointer (&p->attribute_locations, g_hash_table_unref);
glDeleteProgram (p->program_id);
g_slice_free (ShaderProgram, data);
}
static ShaderProgram *
shader_program_new (int program_id)
{
ShaderProgram *p = g_slice_new (ShaderProgram);
p->program_id = program_id;
p->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
p->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
return p;
}
static void
gsk_shader_builder_finalize (GObject *gobject)
{
@ -38,8 +70,7 @@ gsk_shader_builder_finalize (GObject *gobject)
g_clear_pointer (&self->uniforms, g_ptr_array_unref);
g_clear_pointer (&self->attributes, g_ptr_array_unref);
g_clear_pointer (&self->uniform_locations, g_hash_table_unref);
g_clear_pointer (&self->attribute_locations, g_hash_table_unref);
g_clear_pointer (&self->programs, g_hash_table_unref);
G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
}
@ -57,8 +88,9 @@ gsk_shader_builder_init (GskShaderBuilder *self)
self->uniforms = g_ptr_array_new_with_free_func (g_free);
self->attributes = g_ptr_array_new_with_free_func (g_free);
self->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
self->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
self->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL,
shader_program_free);
}
GskShaderBuilder *
@ -77,6 +109,26 @@ gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
builder->resource_base_path = g_strdup (base_path);
}
void
gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
const char *vertex_preamble)
{
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
g_free (builder->vertex_preamble);
builder->vertex_preamble = g_strdup (vertex_preamble);
}
void
gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
const char *fragment_preamble)
{
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
g_free (builder->fragment_preamble);
builder->fragment_preamble = g_strdup (fragment_preamble);
}
void
gsk_shader_builder_set_version (GskShaderBuilder *builder,
int version)
@ -150,7 +202,7 @@ lookup_shader_code (GString *code,
return TRUE;
}
int
static int
gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
int shader_type,
const char *shader_preamble,
@ -163,9 +215,6 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
int status;
int i;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
g_return_val_if_fail (shader_source != NULL, -1);
code = g_string_new (NULL);
if (builder->version > 0)
@ -249,16 +298,16 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
static void
gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
int program_id)
ShaderProgram *program)
{
int i;
for (i = 0; i < builder->uniforms->len; i++)
{
const char *uniform = g_ptr_array_index (builder->uniforms, i);
int loc = glGetUniformLocation (program_id, uniform);
int loc = glGetUniformLocation (program->program_id, uniform);
g_hash_table_insert (builder->uniform_locations,
g_hash_table_insert (program->uniform_locations,
GINT_TO_POINTER (g_quark_from_string (uniform)),
GINT_TO_POINTER (loc));
}
@ -266,16 +315,16 @@ gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
static void
gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
int program_id)
ShaderProgram *program)
{
int i;
for (i = 0; i < builder->attributes->len; i++)
{
const char *attribute = g_ptr_array_index (builder->attributes, i);
int loc = glGetAttribLocation (program_id, attribute);
int loc = glGetAttribLocation (program->program_id, attribute);
g_hash_table_insert (builder->attribute_locations,
g_hash_table_insert (program->attribute_locations,
GINT_TO_POINTER (g_quark_from_string (attribute)),
GINT_TO_POINTER (loc));
}
@ -283,16 +332,35 @@ gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
int
gsk_shader_builder_create_program (GskShaderBuilder *builder,
int vertex_id,
int fragment_id,
const char *vertex_shader,
const char *fragment_shader,
GError **error)
{
ShaderProgram *program;
int vertex_id, fragment_id;
int program_id;
int status;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
g_return_val_if_fail (vertex_id > 0, -1);
g_return_val_if_fail (fragment_id > 0, -1);
g_return_val_if_fail (vertex_shader != NULL, -1);
g_return_val_if_fail (fragment_shader != NULL, -1);
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
builder->vertex_preamble,
vertex_shader,
error);
if (vertex_id < 0)
return -1;
fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
builder->fragment_preamble,
fragment_shader,
error);
if (fragment_id < 0)
{
glDeleteShader (vertex_id);
return -1;
}
program_id = glCreateProgram ();
glAttachShader (program_id, vertex_id);
@ -320,10 +388,11 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
goto out;
}
gsk_shader_builder_cache_uniforms (builder, program_id);
gsk_shader_builder_cache_attributes (builder, program_id);
program = shader_program_new (program_id);
gsk_shader_builder_cache_uniforms (builder, program);
gsk_shader_builder_cache_attributes (builder, program);
builder->program_id = program_id;
g_hash_table_insert (builder->programs, GINT_TO_POINTER (program_id), program);
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK (OPENGL))
@ -331,7 +400,7 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
GHashTableIter iter;
gpointer name_p, location_p;
g_hash_table_iter_init (&iter, builder->uniform_locations);
g_hash_table_iter_init (&iter, program->uniform_locations);
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
{
g_print ("Uniform '%s' - location: %d\n",
@ -339,7 +408,7 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
GPOINTER_TO_INT (location_p));
}
g_hash_table_iter_init (&iter, builder->attribute_locations);
g_hash_table_iter_init (&iter, program->attribute_locations);
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
{
g_print ("Attribute '%s' - location: %d\n",
@ -350,27 +419,40 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
#endif
out:
glDetachShader (program_id, vertex_id);
glDetachShader (program_id, fragment_id);
if (vertex_id > 0)
{
glDetachShader (program_id, vertex_id);
glDeleteShader (vertex_id);
}
if (fragment_id > 0)
{
glDetachShader (program_id, fragment_id);
glDeleteShader (fragment_id);
}
return program_id;
}
int
gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
int program_id,
GQuark uniform_quark)
{
ShaderProgram *p = NULL;
gpointer loc_p = NULL;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
if (builder->program_id < 0)
return -1;
g_return_val_if_fail (program_id >= 0, -1);
if (builder->uniforms->len == 0)
return -1;
if (g_hash_table_lookup_extended (builder->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
if (p == NULL)
return -1;
if (g_hash_table_lookup_extended (p->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
return GPOINTER_TO_INT (loc_p);
return -1;
@ -378,28 +460,24 @@ gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
int
gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
int program_id,
GQuark attribute_quark)
{
ShaderProgram *p = NULL;
gpointer loc_p = NULL;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
if (builder->program_id < 0)
return -1;
g_return_val_if_fail (program_id >= 0, -1);
if (builder->attributes->len == 0)
return -1;
if (g_hash_table_lookup_extended (builder->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
if (p == NULL)
return -1;
if (g_hash_table_lookup_extended (p->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
return GPOINTER_TO_INT (loc_p);
return -1;
}
int
gsk_shader_builder_get_program (GskShaderBuilder *builder)
{
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
return builder->program_id;
}

View File

@ -16,6 +16,10 @@ void gsk_shader_builder_set_version (GskShad
int version);
void gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
const char *base_path);
void gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
const char *shader_preamble);
void gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
const char *shader_preamble);
GQuark gsk_shader_builder_add_uniform (GskShaderBuilder *builder,
const char *uniform_name);
@ -25,20 +29,16 @@ void gsk_shader_builder_add_define (GskShad
const char *define_name,
const char *define_value);
int gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
int shader_type,
const char *shader_preamble,
const char *shader_source,
GError **error);
int gsk_shader_builder_create_program (GskShaderBuilder *builder,
int vertex_id,
int fragment_id,
const char *vertex_shader,
const char *fragment_shader,
GError **error);
int gsk_shader_builder_get_program (GskShaderBuilder *builder);
int gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
int program_id,
GQuark uniform_quark);
int gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
int program_id,
GQuark attribute_quark);
G_END_DECLS