mirror of
https://github.com/brl/mutter.git
synced 2025-02-16 13:24:09 +00:00
cogl-pipeline: Use the pipeline cache for the GLSL backends
The CoglPipelineCache is now extended to store templates for state affecting vertex shaders and combined programs. The GLSL fragend, vertend and progend now uses this to get cached shaders and a program. When a new pipeline is created it will now get hashed three times if the GLSL backends are in use (once for the fragend, once for the vertend and once for the progend). Ideally we should add some way for the progend to check its cache before the fragends and vertends are checked so that it can bypass them entirely if it can find a cached combined program.
This commit is contained in:
parent
461bff1867
commit
f3b90d1717
@ -36,6 +36,7 @@
|
||||
struct _CoglPipelineCache
|
||||
{
|
||||
GHashTable *fragment_hash;
|
||||
GHashTable *vertex_hash;
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
@ -74,6 +75,32 @@ pipeline_fragment_equal (const void *a, const void *b)
|
||||
0);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
pipeline_vertex_hash (const void *data)
|
||||
{
|
||||
unsigned long vertex_state =
|
||||
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||
unsigned long layer_vertex_state =
|
||||
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||
|
||||
return _cogl_pipeline_hash ((CoglPipeline *)data,
|
||||
vertex_state, layer_vertex_state,
|
||||
0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pipeline_vertex_equal (const void *a, const void *b)
|
||||
{
|
||||
unsigned long vertex_state =
|
||||
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||
unsigned long layer_vertex_state =
|
||||
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||
|
||||
return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b,
|
||||
vertex_state, layer_vertex_state,
|
||||
0);
|
||||
}
|
||||
|
||||
CoglPipelineCache *
|
||||
cogl_pipeline_cache_new (void)
|
||||
{
|
||||
@ -83,6 +110,10 @@ cogl_pipeline_cache_new (void)
|
||||
pipeline_fragment_equal,
|
||||
cogl_object_unref,
|
||||
cogl_object_unref);
|
||||
cache->vertex_hash = g_hash_table_new_full (pipeline_vertex_hash,
|
||||
pipeline_vertex_equal,
|
||||
cogl_object_unref,
|
||||
cogl_object_unref);
|
||||
|
||||
return cache;
|
||||
}
|
||||
@ -91,6 +122,7 @@ void
|
||||
cogl_pipeline_cache_free (CoglPipelineCache *cache)
|
||||
{
|
||||
g_hash_table_destroy (cache->fragment_hash);
|
||||
g_hash_table_destroy (cache->vertex_hash);
|
||||
g_free (cache);
|
||||
}
|
||||
|
||||
@ -144,3 +176,61 @@ _cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache,
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
CoglPipeline *
|
||||
_cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache,
|
||||
CoglPipeline *key_pipeline)
|
||||
{
|
||||
CoglPipeline *template =
|
||||
g_hash_table_lookup (cache->vertex_hash, key_pipeline);
|
||||
|
||||
if (template == NULL)
|
||||
{
|
||||
template = cogl_pipeline_copy (key_pipeline);
|
||||
|
||||
g_hash_table_insert (cache->vertex_hash,
|
||||
template,
|
||||
cogl_object_ref (template));
|
||||
|
||||
if (G_UNLIKELY (g_hash_table_size (cache->vertex_hash) > 50))
|
||||
{
|
||||
static gboolean seen = FALSE;
|
||||
if (!seen)
|
||||
g_warning ("Over 50 separate vertex shaders have been "
|
||||
"generated which is very unusual, so something "
|
||||
"is probably wrong!\n");
|
||||
seen = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
CoglPipeline *
|
||||
_cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache,
|
||||
CoglPipeline *key_pipeline)
|
||||
{
|
||||
unsigned int pipeline_state_for_fragment_codegen;
|
||||
unsigned int pipeline_layer_state_for_fragment_codegen;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
pipeline_state_for_fragment_codegen =
|
||||
_cogl_pipeline_get_state_for_fragment_codegen (ctx);
|
||||
pipeline_layer_state_for_fragment_codegen =
|
||||
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx);
|
||||
|
||||
/* Currently the vertex shader state is a subset of the fragment
|
||||
shader state so we can avoid a third hash table here by just
|
||||
using the fragment shader table. This assert should catch it if
|
||||
that ever changes */
|
||||
|
||||
g_assert ((pipeline_state_for_fragment_codegen |
|
||||
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN) ==
|
||||
pipeline_state_for_fragment_codegen);
|
||||
g_assert ((pipeline_layer_state_for_fragment_codegen |
|
||||
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN) ==
|
||||
pipeline_layer_state_for_fragment_codegen);
|
||||
|
||||
return _cogl_pipeline_cache_get_fragment_template (cache, key_pipeline);
|
||||
}
|
||||
|
@ -47,4 +47,31 @@ CoglPipeline *
|
||||
_cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache,
|
||||
CoglPipeline *key_pipeline);
|
||||
|
||||
/*
|
||||
* Gets a pipeline from the cache that has the same state as
|
||||
* @key_pipeline for the state in
|
||||
* COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN. If there is no
|
||||
* matching pipline already then a copy of key_pipeline is stored in
|
||||
* the cache so that it will be used next time the function is called
|
||||
* with a similar pipeline. In that case the copy itself will be
|
||||
* returned
|
||||
*/
|
||||
CoglPipeline *
|
||||
_cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache,
|
||||
CoglPipeline *key_pipeline);
|
||||
|
||||
/*
|
||||
* Gets a pipeline from the cache that has the same state as
|
||||
* @key_pipeline for the combination of the state state in
|
||||
* COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN and
|
||||
* COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN. If there is no
|
||||
* matching pipline already then a copy of key_pipeline is stored in
|
||||
* the cache so that it will be used next time the function is called
|
||||
* with a similar pipeline. In that case the copy itself will be
|
||||
* returned
|
||||
*/
|
||||
CoglPipeline *
|
||||
_cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache,
|
||||
CoglPipeline *key_pipeline);
|
||||
|
||||
#endif /* __COGL_PIPELINE_CACHE_H__ */
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "cogl-handle.h"
|
||||
#include "cogl-shader-private.h"
|
||||
#include "cogl-program-private.h"
|
||||
#include "cogl-pipeline-cache.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@ -154,6 +155,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
||||
{
|
||||
CoglPipelineShaderState *shader_state;
|
||||
CoglPipeline *authority;
|
||||
CoglPipeline *template_pipeline = NULL;
|
||||
CoglProgram *user_program;
|
||||
int i;
|
||||
|
||||
@ -197,8 +199,30 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
||||
*/
|
||||
if (shader_state == NULL)
|
||||
{
|
||||
shader_state = shader_state_new (n_layers);
|
||||
/* Check if there is already a similar cached pipeline whose
|
||||
shader state we can share */
|
||||
if (G_LIKELY (!(COGL_DEBUG_ENABLED
|
||||
(COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
|
||||
{
|
||||
template_pipeline =
|
||||
_cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache,
|
||||
authority);
|
||||
|
||||
shader_state = get_shader_state (template_pipeline);
|
||||
}
|
||||
|
||||
if (shader_state)
|
||||
shader_state->ref_count++;
|
||||
else
|
||||
shader_state = shader_state_new (n_layers);
|
||||
|
||||
set_shader_state (authority, shader_state);
|
||||
|
||||
if (template_pipeline)
|
||||
{
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (template_pipeline, shader_state);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the pipeline isn't actually its own glsl-authority
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "cogl-program-private.h"
|
||||
#include "cogl-pipeline-fragend-glsl-private.h"
|
||||
#include "cogl-pipeline-vertend-glsl-private.h"
|
||||
#include "cogl-pipeline-cache.h"
|
||||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
|
||||
@ -538,6 +539,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
||||
gboolean program_changed = FALSE;
|
||||
UpdateUniformsState state;
|
||||
CoglProgram *user_program;
|
||||
CoglPipeline *template_pipeline = NULL;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
@ -570,9 +572,31 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
||||
|
||||
if (program_state == NULL)
|
||||
{
|
||||
program_state
|
||||
= program_state_new (cogl_pipeline_get_n_layers (pipeline));
|
||||
/* Check if there is already a similar cached pipeline whose
|
||||
program state we can share */
|
||||
if (G_LIKELY (!(COGL_DEBUG_ENABLED
|
||||
(COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
|
||||
{
|
||||
template_pipeline =
|
||||
_cogl_pipeline_cache_get_combined_template (ctx->pipeline_cache,
|
||||
authority);
|
||||
|
||||
program_state = get_program_state (template_pipeline);
|
||||
}
|
||||
|
||||
if (program_state)
|
||||
program_state->ref_count++;
|
||||
else
|
||||
program_state
|
||||
= program_state_new (cogl_pipeline_get_n_layers (authority));
|
||||
|
||||
set_program_state (authority, program_state);
|
||||
|
||||
if (template_pipeline)
|
||||
{
|
||||
program_state->ref_count++;
|
||||
set_program_state (template_pipeline, program_state);
|
||||
}
|
||||
}
|
||||
|
||||
if (authority != pipeline)
|
||||
|
@ -128,6 +128,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
||||
unsigned long pipelines_difference)
|
||||
{
|
||||
CoglPipelineShaderState *shader_state;
|
||||
CoglPipeline *template_pipeline = NULL;
|
||||
CoglProgram *user_program;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
@ -164,8 +165,30 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
||||
|
||||
if (shader_state == NULL)
|
||||
{
|
||||
shader_state = shader_state_new ();
|
||||
/* Check if there is already a similar cached pipeline whose
|
||||
shader state we can share */
|
||||
if (G_LIKELY (!(COGL_DEBUG_ENABLED
|
||||
(COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
|
||||
{
|
||||
template_pipeline =
|
||||
_cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache,
|
||||
authority);
|
||||
|
||||
shader_state = get_shader_state (template_pipeline);
|
||||
}
|
||||
|
||||
if (shader_state)
|
||||
shader_state->ref_count++;
|
||||
else
|
||||
shader_state = shader_state_new ();
|
||||
|
||||
set_shader_state (authority, shader_state);
|
||||
|
||||
if (template_pipeline)
|
||||
{
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (template_pipeline, shader_state);
|
||||
}
|
||||
}
|
||||
|
||||
if (authority != pipeline)
|
||||
|
Loading…
x
Reference in New Issue
Block a user