Compare commits
4 Commits
drop-highl
...
shader-cac
Author | SHA1 | Date | |
---|---|---|---|
|
e8d497b83a | ||
|
37767e056f | ||
|
c7e1ab67c6 | ||
|
4a2e73a07c |
@@ -1790,6 +1790,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
|
||||
prog->index = i;
|
||||
prog->id = gsk_shader_builder_create_program (builder,
|
||||
self->gl_context,
|
||||
program_definitions[i].vs,
|
||||
program_definitions[i].fs,
|
||||
&shader_error);
|
||||
@@ -1914,7 +1915,6 @@ static void
|
||||
gsk_gl_renderer_unrealize (GskRenderer *renderer)
|
||||
{
|
||||
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
|
||||
guint i;
|
||||
|
||||
if (self->gl_context == NULL)
|
||||
return;
|
||||
@@ -1926,9 +1926,6 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
|
||||
*/
|
||||
g_array_set_size (self->render_ops, 0);
|
||||
|
||||
for (i = 0; i < GL_N_PROGRAMS; i ++)
|
||||
glDeleteProgram (self->programs[i].id);
|
||||
|
||||
gsk_gl_glyph_cache_free (&self->glyph_cache);
|
||||
|
||||
g_clear_object (&self->gl_profiler);
|
||||
|
202
gsk/gl/gskglshadercache.c
Normal file
202
gsk/gl/gskglshadercache.c
Normal file
@@ -0,0 +1,202 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglshadercacheprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
struct _GskGLShaderCache
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GHashTable *shader_cache;
|
||||
GHashTable *program_cache;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskGLShaderCache, gsk_gl_shader_cache, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gsk_gl_shader_cache_finalize (GObject *gobject)
|
||||
{
|
||||
GskGLShaderCache *self = GSK_GL_SHADER_CACHE (gobject);
|
||||
|
||||
g_clear_pointer (&self->shader_cache, g_hash_table_unref);
|
||||
g_clear_pointer (&self->program_cache, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_shader_cache_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_shader_cache_class_init (GskGLShaderCacheClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS (klass)->finalize = gsk_gl_shader_cache_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_shader_cache_init (GskGLShaderCache *self)
|
||||
{
|
||||
}
|
||||
|
||||
GskGLShaderCache *
|
||||
gsk_gl_shader_cache_new (void)
|
||||
{
|
||||
return g_object_new (GSK_TYPE_GL_SHADER_CACHE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_shader (gpointer data)
|
||||
{
|
||||
int shader_id = GPOINTER_TO_INT (data);
|
||||
|
||||
if (shader_id > 0)
|
||||
glDeleteShader (shader_id);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_program (gpointer data)
|
||||
{
|
||||
int program_id = GPOINTER_TO_INT (data);
|
||||
|
||||
if (program_id > 0)
|
||||
glDeleteProgram (program_id);
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_shader_cache_compile_shader (GskGLShaderCache *cache,
|
||||
int shader_type,
|
||||
const char *source,
|
||||
GError **error)
|
||||
{
|
||||
if (cache->shader_cache == NULL)
|
||||
cache->shader_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free,
|
||||
delete_shader);
|
||||
|
||||
char *shasum = g_compute_checksum_for_string (G_CHECKSUM_SHA256, source, -1);
|
||||
|
||||
int shader_id = GPOINTER_TO_INT (g_hash_table_lookup (cache->shader_cache, shasum));
|
||||
|
||||
if (shader_id != 0)
|
||||
{
|
||||
GSK_NOTE (SHADERS,
|
||||
g_debug ("*** Cache hit for %s shader (checksum: %s) ***\n"
|
||||
"%*s%s\n",
|
||||
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
shasum,
|
||||
64, source,
|
||||
strlen (source) < 64 ? "" : "..."));
|
||||
g_free (shasum);
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
shader_id = glCreateShader (shader_type);
|
||||
glShaderSource (shader_id, 1, (const GLchar **) &source, NULL);
|
||||
glCompileShader (shader_id);
|
||||
|
||||
GSK_NOTE (SHADERS,
|
||||
g_debug ("*** Compiling %s shader ***\n"
|
||||
"%*s%s\n",
|
||||
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
64, source,
|
||||
strlen (source) < 64 ? "" : "..."));
|
||||
|
||||
int status = GL_FALSE;
|
||||
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
int log_len = 0;
|
||||
glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
char *buffer = g_malloc0 (log_len + 1);
|
||||
glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
|
||||
"Compilation failure in %s shader:\n%s",
|
||||
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
buffer);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteShader (shader_id);
|
||||
shader_id = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_hash_table_insert (cache->shader_cache,
|
||||
shasum,
|
||||
GINT_TO_POINTER (shader_id));
|
||||
}
|
||||
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_shader_cache_link_program (GskGLShaderCache *cache,
|
||||
int vertex_shader,
|
||||
int fragment_shader,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (vertex_shader > 0 && fragment_shader > 0, -1);
|
||||
|
||||
if (cache->program_cache == NULL)
|
||||
cache->program_cache = g_hash_table_new_full (g_int64_hash, g_int64_equal,
|
||||
g_free,
|
||||
delete_program);
|
||||
|
||||
gint64 *key = g_new (gint64, 1);
|
||||
|
||||
*key = (gint64) vertex_shader << 31 | fragment_shader;
|
||||
|
||||
int program_id = GPOINTER_TO_INT (g_hash_table_lookup (cache->program_cache, key));
|
||||
if (program_id > 0)
|
||||
{
|
||||
GSK_NOTE (SHADERS,
|
||||
g_debug ("*** Cache hit for program (vertex: %d, fragment: %d) ***",
|
||||
vertex_shader,
|
||||
fragment_shader));
|
||||
g_free (key);
|
||||
return program_id;
|
||||
}
|
||||
|
||||
program_id = glCreateProgram ();
|
||||
|
||||
GSK_NOTE (SHADERS,
|
||||
g_debug ("*** Linking %d, %d shaders ***\n",
|
||||
vertex_shader,
|
||||
fragment_shader));
|
||||
|
||||
glAttachShader (program_id, vertex_shader);
|
||||
glAttachShader (program_id, fragment_shader);
|
||||
glLinkProgram (program_id);
|
||||
|
||||
int status = GL_FALSE;
|
||||
glGetProgramiv (program_id, GL_LINK_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
int log_len = 0;
|
||||
glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
char *buffer = g_malloc0 (log_len + 1);
|
||||
glGetProgramInfoLog (program_id, log_len, NULL, buffer);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
|
||||
"Linking failure in shader:\n%s", buffer);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteProgram (program_id);
|
||||
program_id = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
glDetachShader (program_id, vertex_shader);
|
||||
glDetachShader (program_id, fragment_shader);
|
||||
|
||||
g_hash_table_insert (cache->program_cache,
|
||||
key,
|
||||
GINT_TO_POINTER (program_id));
|
||||
}
|
||||
|
||||
return program_id;
|
||||
}
|
23
gsk/gl/gskglshadercacheprivate.h
Normal file
23
gsk/gl/gskglshadercacheprivate.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_SHADER_CACHE (gsk_gl_shader_cache_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GskGLShaderCache, gsk_gl_shader_cache, GSK, GL_SHADER_CACHE, GObject)
|
||||
|
||||
GskGLShaderCache * gsk_gl_shader_cache_new (void);
|
||||
|
||||
int gsk_gl_shader_cache_compile_shader (GskGLShaderCache *cache,
|
||||
int shader_type,
|
||||
const char *code,
|
||||
GError **error);
|
||||
int gsk_gl_shader_cache_link_program (GskGLShaderCache *cache,
|
||||
int vertex_shader,
|
||||
int fragment_shader,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
@@ -3,6 +3,7 @@
|
||||
#include "gskshaderbuilderprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskglshadercacheprivate.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <epoxy/gl.h>
|
||||
@@ -18,8 +19,6 @@ struct _GskShaderBuilder
|
||||
int version;
|
||||
|
||||
GPtrArray *defines;
|
||||
GPtrArray *uniforms;
|
||||
GPtrArray *attributes;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskShaderBuilder, gsk_shader_builder, G_TYPE_OBJECT)
|
||||
@@ -137,6 +136,7 @@ lookup_shader_code (GString *code,
|
||||
|
||||
static int
|
||||
gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
|
||||
GskGLShaderCache *cache,
|
||||
int shader_type,
|
||||
const char *shader_preamble,
|
||||
const char *shader_source,
|
||||
@@ -145,7 +145,6 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
|
||||
GString *code;
|
||||
char *source;
|
||||
int shader_id;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
code = g_string_new (NULL);
|
||||
@@ -188,117 +187,56 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
|
||||
|
||||
source = g_string_free (code, FALSE);
|
||||
|
||||
shader_id = glCreateShader (shader_type);
|
||||
glShaderSource (shader_id, 1, (const GLchar **) &source, NULL);
|
||||
glCompileShader (shader_id);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_DEBUG_CHECK (SHADERS))
|
||||
{
|
||||
g_print ("*** Compiling %s shader from '%s' + '%s' ***\n"
|
||||
"%s\n",
|
||||
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
shader_preamble, shader_source,
|
||||
source);
|
||||
}
|
||||
#endif
|
||||
shader_id = gsk_gl_shader_cache_compile_shader (cache,
|
||||
shader_type, source,
|
||||
error);
|
||||
|
||||
g_free (source);
|
||||
|
||||
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
int log_len;
|
||||
char *buffer;
|
||||
|
||||
glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
buffer = g_malloc0 (log_len + 1);
|
||||
glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
|
||||
"Compilation failure in %s shader:\n%s",
|
||||
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
buffer);
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteShader (shader_id);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_shader_builder_create_program (GskShaderBuilder *builder,
|
||||
GdkGLContext *gl_context,
|
||||
const char *vertex_shader,
|
||||
const char *fragment_shader,
|
||||
GError **error)
|
||||
{
|
||||
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_shader != NULL, -1);
|
||||
g_return_val_if_fail (fragment_shader != NULL, -1);
|
||||
|
||||
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
|
||||
GskGLShaderCache *cache = g_object_get_data (G_OBJECT (gl_context), "-gsk-gl-shader-cache");
|
||||
if (cache == NULL)
|
||||
{
|
||||
cache = gsk_gl_shader_cache_new ();
|
||||
g_object_set_data_full (G_OBJECT (gl_context),
|
||||
"-gsk-gl-shader-cache",
|
||||
cache,
|
||||
(GDestroyNotify) g_object_unref);
|
||||
}
|
||||
|
||||
vertex_id = gsk_shader_builder_compile_shader (builder, cache,
|
||||
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,
|
||||
fragment_id = gsk_shader_builder_compile_shader (builder, cache,
|
||||
GL_FRAGMENT_SHADER,
|
||||
builder->fragment_preamble,
|
||||
fragment_shader,
|
||||
error);
|
||||
if (fragment_id < 0)
|
||||
{
|
||||
glDeleteShader (vertex_id);
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
|
||||
program_id = glCreateProgram ();
|
||||
glAttachShader (program_id, vertex_id);
|
||||
glAttachShader (program_id, fragment_id);
|
||||
glLinkProgram (program_id);
|
||||
|
||||
glGetProgramiv (program_id, GL_LINK_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
int log_len = 0;
|
||||
|
||||
glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
buffer = g_malloc0 (log_len + 1);
|
||||
glGetProgramInfoLog (program_id, log_len, NULL, buffer);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
|
||||
"Linking failure in shader:\n%s", buffer);
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteProgram (program_id);
|
||||
program_id = -1;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
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;
|
||||
return gsk_gl_shader_cache_link_program (cache,
|
||||
vertex_id,
|
||||
fragment_id,
|
||||
error);
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ void gsk_shader_builder_add_define (GskShad
|
||||
const char *define_value);
|
||||
|
||||
int gsk_shader_builder_create_program (GskShaderBuilder *builder,
|
||||
GdkGLContext *gl_context,
|
||||
const char *vertex_shader,
|
||||
const char *fragment_shader,
|
||||
GError **error);
|
||||
|
@@ -25,7 +25,7 @@ gsk_public_sources = files([
|
||||
'gskrenderer.c',
|
||||
'gskrendernode.c',
|
||||
'gskrendernodeimpl.c',
|
||||
'gskroundedrect.c'
|
||||
'gskroundedrect.c',
|
||||
])
|
||||
|
||||
gsk_private_sources = files([
|
||||
@@ -34,13 +34,14 @@ gsk_private_sources = files([
|
||||
'gskdebug.c',
|
||||
'gskprivate.c',
|
||||
'gskprofiler.c',
|
||||
'gl/gskshaderbuilder.c',
|
||||
'gl/gskglprofiler.c',
|
||||
'gl/gskglrenderer.c',
|
||||
'gl/gskgldriver.c',
|
||||
'gl/gskglglyphcache.c',
|
||||
'gl/gskglimage.c',
|
||||
'gl/gskgldriver.c',
|
||||
'gl/gskglrenderops.c'
|
||||
'gl/gskglprofiler.c',
|
||||
'gl/gskglrenderer.c',
|
||||
'gl/gskglrenderops.c',
|
||||
'gl/gskglshadercache.c',
|
||||
'gl/gskshaderbuilder.c',
|
||||
])
|
||||
|
||||
gsk_public_headers = files([
|
||||
@@ -49,7 +50,7 @@ gsk_public_headers = files([
|
||||
'gskrendernode.h',
|
||||
'gskroundedrect.h',
|
||||
'gsktypes.h',
|
||||
'gsk-autocleanup.h'
|
||||
'gsk-autocleanup.h',
|
||||
])
|
||||
|
||||
install_headers(gsk_public_headers, 'gsk.h', subdir: 'gtk-4.0/gsk')
|
||||
|
Reference in New Issue
Block a user