1
0
Fork 0

Clearly define 3 progends that own the frag+vertends

This adds a new "fixed-arbfp" progend so we now have 3 distinct ways of
setting up the state of a pipeline:

  » fixed; where the vertex and fragment processing are implemented
    using fixed function opengl apis.
  » fixed-arbfp; where vertex processing is implemented using fixed
    function opengl apis but fragment processing is implemented
    using the ARB Fragment Processing language.
  » glsl; there vertex and fragment processing are both implemented
    using glsl.

This means we avoid unusual, combinations such as glsl for vertex
processing and arbfp for fragment processing, and also avoid pairing
fixed-function vertex processing with glsl fragment processing which we
happen to know hits some awkward code paths in Mesa that lead to poor
performance.

As part of this change, the progend now implies specific vertend and
fragend choices so instead of associating a vertend and fragend with a
pipeline we now just associate a progend choice.

When flushing a pipeline and choosing what progend to use, we now call a
progend->start() method that is able to determine if the vertend and
fragend together will be able to handle the given pipeline so the
vertend and fragend ->start() methods no longer need to return a boolean
status.

Since we now don't need to support glsl used in conjunction with fixed
function this will allow us to avoid ever using OpenGL builtin attribute
names, though this patch doesn't change that yet.

Reviewed-by: Neil Roberts <neil@linux.intel.com>

(cherry picked from commit cec381f50c7a2f2186bd4a8c5f38fecd5f099075)
This commit is contained in:
Robert Bragg 2012-09-25 21:08:10 +01:00
parent f05a1a62f4
commit 8f3380adc3
14 changed files with 391 additions and 358 deletions

View file

@ -175,6 +175,8 @@ cogl_driver_sources += \
$(srcdir)/driver/gl/cogl-pipeline-fragend-glsl-private.h \
$(srcdir)/driver/gl/gl/cogl-pipeline-fragend-arbfp.c \
$(srcdir)/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h \
$(srcdir)/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c \
$(srcdir)/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h \
$(srcdir)/driver/gl/cogl-pipeline-fragend-fixed.c \
$(srcdir)/driver/gl/cogl-pipeline-fragend-fixed-private.h \
$(srcdir)/driver/gl/cogl-pipeline-vertend-glsl.c \

View file

@ -45,9 +45,10 @@
#ifdef HAVE_COGL_GL
#define COGL_PIPELINE_PROGEND_FIXED 0
#define COGL_PIPELINE_PROGEND_GLSL 1
#define COGL_PIPELINE_N_PROGENDS 2
#define COGL_PIPELINE_PROGEND_FIXED_ARBFP 0
#define COGL_PIPELINE_PROGEND_FIXED 1
#define COGL_PIPELINE_PROGEND_GLSL 2
#define COGL_PIPELINE_N_PROGENDS 3
#define COGL_PIPELINE_VERTEND_FIXED 0
#define COGL_PIPELINE_VERTEND_GLSL 1
@ -97,11 +98,8 @@
#endif /* HAVE_COGL_GL */
#define COGL_PIPELINE_FRAGEND_DEFAULT 0
#define COGL_PIPELINE_FRAGEND_UNDEFINED 3
#define COGL_PIPELINE_VERTEND_DEFAULT 0
#define COGL_PIPELINE_VERTEND_UNDEFINED 3
#define COGL_PIPELINE_PROGEND_DEFAULT 0
#define COGL_PIPELINE_PROGEND_UNDEFINED 3
/* XXX: should I rename these as
* COGL_PIPELINE_STATE_INDEX_XYZ... ?
@ -480,20 +478,19 @@ struct _CoglPipeline
* where the pipeline originates from */
unsigned int has_static_breadcrumb:1;
/* There are multiple fragment processing backends for CoglPipeline,
* glsl, arbfp and fixed. This identifies the backend being used for
* the pipeline and any private state the backend has associated
* with the pipeline. */
unsigned int fragend:3;
unsigned int vertend:3;
/* There are multiple fragment and vertex processing backends for
* CoglPipeline, glsl, arbfp and fixed that are bundled under a
* "progend". This identifies the backend being used for the
* pipeline. */
unsigned int progend:3;
};
typedef struct _CoglPipelineFragend
{
CoglBool (*start) (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
int n_tex_coord_attribs);
void (*start) (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
int n_tex_coord_attribs);
CoglBool (*add_layer) (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference);
@ -512,10 +509,10 @@ typedef struct _CoglPipelineFragend
typedef struct _CoglPipelineVertend
{
CoglBool (*start) (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
int n_tex_coord_attribs);
void (*start) (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
int n_tex_coord_attribs);
CoglBool (*add_layer) (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference,
@ -533,6 +530,9 @@ typedef struct _CoglPipelineVertend
typedef struct
{
int vertend;
int fragend;
CoglBool (*start) (CoglPipeline *pipeline);
void (*end) (CoglPipeline *pipeline,
unsigned long pipelines_difference,
int n_tex_coord_attribs);
@ -818,10 +818,7 @@ _cogl_pipeline_weak_copy (CoglPipeline *pipeline,
void *user_data);
void
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend);
void
_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend);
_cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend);
CoglPipeline *
_cogl_pipeline_get_parent (CoglPipeline *pipeline);

View file

@ -1111,10 +1111,7 @@ cogl_pipeline_set_user_program (CoglPipeline *pipeline,
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
if (program != COGL_INVALID_HANDLE)
{
_cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
_cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
}
_cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_UNDEFINED);
/* If we are the current authority see if we can revert to one of our
* ancestors being the authority */

View file

@ -79,6 +79,9 @@ _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)];
#include "cogl-pipeline-vertend-fixed-private.h"
#endif
#ifdef COGL_PIPELINE_PROGEND_FIXED_ARBFP
#include "cogl-pipeline-progend-fixed-arbfp-private.h"
#endif
#ifdef COGL_PIPELINE_PROGEND_FIXED
#include "cogl-pipeline-progend-fixed-private.h"
#endif
@ -125,6 +128,10 @@ _cogl_pipeline_init_default_pipeline (void)
_cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_FIXED] =
&_cogl_pipeline_fixed_fragend;
#endif
#ifdef COGL_PIPELINE_PROGEND_FIXED
_cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED_ARBFP] =
&_cogl_pipeline_fixed_arbfp_progend;
#endif
#ifdef COGL_PIPELINE_PROGEND_FIXED
_cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED] =
&_cogl_pipeline_fixed_progend;
@ -147,8 +154,7 @@ _cogl_pipeline_init_default_pipeline (void)
pipeline->is_weak = FALSE;
pipeline->journal_ref_count = 0;
pipeline->fragend = COGL_PIPELINE_FRAGEND_UNDEFINED;
pipeline->vertend = COGL_PIPELINE_VERTEND_UNDEFINED;
pipeline->progend = COGL_PIPELINE_PROGEND_UNDEFINED;
pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE;
pipeline->real_blend_enable = FALSE;
@ -284,12 +290,17 @@ _cogl_pipeline_set_parent (CoglPipeline *pipeline,
* that depends on the pipeline's ancestry then it may be notified
* here...
*/
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
_cogl_pipeline_fragends[pipeline->fragend]->pipeline_set_parent_notify)
if (pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
{
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[pipeline->progend];
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[pipeline->fragend];
fragend->pipeline_set_parent_notify (pipeline);
_cogl_pipeline_fragends[progend->fragend];
/* Currently only the fragends ever care about reparenting of
* pipelines... */
if (fragend->pipeline_set_parent_notify)
fragend->pipeline_set_parent_notify (pipeline);
}
}
@ -368,9 +379,7 @@ _cogl_pipeline_copy (CoglPipeline *src, CoglBool is_weak)
pipeline->deprecated_get_layers_list = NULL;
pipeline->deprecated_get_layers_list_dirty = TRUE;
pipeline->fragend = src->fragend;
pipeline->vertend = src->vertend;
pipeline->progend = src->progend;
pipeline->has_static_breadcrumb = FALSE;
@ -831,15 +840,9 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline,
}
void
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend)
_cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend)
{
pipeline->fragend = fragend;
}
void
_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend)
{
pipeline->vertend = vertend;
pipeline->progend = progend;
}
static void
@ -1191,46 +1194,37 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
*
* All STATE_LAYERS change notification with the exception of
* ->n_layers will also result in layer_pre_change_notifications.
* For backends that perform code generation for fragment
* processing they typically need to understand the details of how
* layers get changed to determine if they need to repeat codegen.
* It doesn't help them to
* report a pipeline STATE_LAYERS change for all layer changes since
* it's so broad, they really need to wait for the specific layer
* change to be notified. What does help though is to report a
* STATE_LAYERS change for a change in
* ->n_layers because they typically do need to repeat codegen in
* that case.
* For backends that perform code generation for fragment processing
* they typically need to understand the details of how layers get
* changed to determine if they need to repeat codegen. It doesn't
* help them to report a pipeline STATE_LAYERS change for all layer
* changes since it's so broad, they really need to wait for the
* specific layer change to be notified. What does help though is
* to report a STATE_LAYERS change for a change in ->n_layers
* because they typically do need to repeat codegen in that case.
*
* Here we ensure that change notifications against a pipeline or
* against a layer are mutually exclusive as far as fragment, vertex
* and program backends are concerned.
*/
if (!from_layer_change)
if (!from_layer_change &&
pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
{
int i;
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[pipeline->progend];
const CoglPipelineVertend *vertend =
_cogl_pipeline_vertends[progend->vertend];
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[progend->fragend];
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
_cogl_pipeline_fragends[pipeline->fragend]->pipeline_pre_change_notify)
{
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[pipeline->fragend];
fragend->pipeline_pre_change_notify (pipeline, change, new_color);
}
if (vertend->pipeline_pre_change_notify)
vertend->pipeline_pre_change_notify (pipeline, change, new_color);
if (pipeline->vertend != COGL_PIPELINE_VERTEND_UNDEFINED &&
_cogl_pipeline_vertends[pipeline->vertend]->pipeline_pre_change_notify)
{
const CoglPipelineVertend *vertend =
_cogl_pipeline_vertends[pipeline->vertend];
vertend->pipeline_pre_change_notify (pipeline, change, new_color);
}
if (fragend->pipeline_pre_change_notify)
fragend->pipeline_pre_change_notify (pipeline, change, new_color);
for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
if (_cogl_pipeline_progends[i]->pipeline_pre_change_notify)
_cogl_pipeline_progends[i]->pipeline_pre_change_notify (pipeline,
change,
new_color);
if (progend->pipeline_pre_change_notify)
progend->pipeline_pre_change_notify (pipeline, change, new_color);
}
/* There may be an arbitrary tree of descendants of this pipeline;
@ -1546,12 +1540,15 @@ _cogl_pipeline_fragend_layer_change_notify (CoglPipeline *owner,
* have a single owner and can only be associated with a single
* backend that needs to be notified of the layer change...
*/
if (owner->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
_cogl_pipeline_fragends[owner->fragend]->layer_pre_change_notify)
if (owner->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
{
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[owner->progend];
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[owner->fragend];
fragend->layer_pre_change_notify (owner, layer, change);
_cogl_pipeline_fragends[progend->fragend];
if (fragend->layer_pre_change_notify)
fragend->layer_pre_change_notify (owner, layer, change);
}
}
@ -1561,12 +1558,15 @@ _cogl_pipeline_vertend_layer_change_notify (CoglPipeline *owner,
CoglPipelineLayerState change)
{
/* NB: The comment in fragend_layer_change_notify applies here too */
if (owner->vertend != COGL_PIPELINE_VERTEND_UNDEFINED &&
_cogl_pipeline_vertends[owner->vertend]->layer_pre_change_notify)
if (owner->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
{
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[owner->progend];
const CoglPipelineVertend *vertend =
_cogl_pipeline_vertends[owner->vertend];
vertend->layer_pre_change_notify (owner, layer, change);
_cogl_pipeline_vertends[progend->vertend];
if (vertend->layer_pre_change_notify)
vertend->layer_pre_change_notify (owner, layer, change);
}
}
@ -1575,15 +1575,11 @@ _cogl_pipeline_progend_layer_change_notify (CoglPipeline *owner,
CoglPipelineLayer *layer,
CoglPipelineLayerState change)
{
int i;
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[owner->progend];
/* Give all of the progends a chance to notice that the layer has
changed */
for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
if (_cogl_pipeline_progends[i]->layer_pre_change_notify)
_cogl_pipeline_progends[i]->layer_pre_change_notify (owner,
layer,
change);
if (progend->layer_pre_change_notify)
progend->layer_pre_change_notify (owner, layer, change);
}
typedef struct

View file

@ -89,37 +89,13 @@ get_max_texture_units (void)
return ctx->max_texture_units;
}
static CoglBool
static void
_cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglHandle user_program;
_COGL_GET_CONTEXT (ctx, FALSE);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
return FALSE;
if (ctx->driver == COGL_DRIVER_GLES2)
return FALSE;
/* Fragment snippets are only supported in the GLSL fragend */
if (_cogl_pipeline_has_fragment_snippets (pipeline))
return FALSE;
/* If there is a user program with a fragment shader then the
appropriate backend for that language should handle it. We can
still use the fixed fragment backend if the program only contains
a vertex shader */
user_program = cogl_pipeline_get_user_program (pipeline);
if (user_program != COGL_INVALID_HANDLE &&
_cogl_program_has_fragment_shader (user_program))
return FALSE;
_cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
return TRUE;
}
static void

View file

@ -213,7 +213,7 @@ has_replace_hook (CoglPipelineLayer *layer,
return FALSE;
}
static CoglBool
static void
_cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
@ -222,22 +222,10 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
CoglPipelineShaderState *shader_state;
CoglPipeline *authority;
CoglPipeline *template_pipeline = NULL;
CoglProgram *user_program;
CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
int i;
_COGL_GET_CONTEXT (ctx, FALSE);
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
return FALSE;
user_program = cogl_pipeline_get_user_program (pipeline);
/* If the user fragment shader isn't GLSL then we should let
another backend handle it */
if (user_program &&
_cogl_program_has_fragment_shader (user_program) &&
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
return FALSE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Now lookup our glsl backend private state */
shader_state = get_shader_state (pipeline);
@ -313,7 +301,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
shader_state->user_program_age == user_program->age)
&& (ctx->driver != COGL_DRIVER_GLES2 ||
shader_state->n_tex_coord_attribs == n_tex_coord_attribs))
return TRUE;
return;
/* We need to recreate the shader so destroy the existing one */
GE( ctx, glDeleteShader (shader_state->gl_shader) );
@ -333,7 +321,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
to generate one */
if (user_program &&
_cogl_program_has_fragment_shader (user_program))
return TRUE;
return;
/* We reuse two grow-only GStrings for code-gen. One string
contains the uniform and attribute declarations while the
@ -356,8 +344,6 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
shader_state->unit_state[i].sampled = FALSE;
shader_state->unit_state[i].combine_constant_used = FALSE;
}
return TRUE;
}
static void

View file

@ -1035,28 +1035,30 @@ compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data)
typedef struct
{
CoglFramebuffer *framebuffer;
const CoglPipelineVertend *vertend;
const CoglPipelineFragend *fragend;
CoglPipeline *pipeline;
unsigned long *layer_differences;
CoglBool error_adding_layer;
CoglBool added_layer;
} CoglPipelineFragendAddLayerState;
} CoglPipelineAddLayerState;
static CoglBool
fragend_add_layer_cb (CoglPipelineLayer *layer,
vertend_add_layer_cb (CoglPipelineLayer *layer,
void *user_data)
{
CoglPipelineFragendAddLayerState *state = user_data;
const CoglPipelineFragend *fragend = state->fragend;
CoglPipelineAddLayerState *state = user_data;
const CoglPipelineVertend *vertend = state->vertend;
CoglPipeline *pipeline = state->pipeline;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
/* Either generate per layer code snippets or setup the
* fixed function glTexEnv for each layer... */
if (G_LIKELY (fragend->add_layer (pipeline,
if (G_LIKELY (vertend->add_layer (pipeline,
layer,
state->layer_differences[unit_index])))
state->layer_differences[unit_index],
state->framebuffer)))
state->added_layer = TRUE;
else
{
@ -1067,32 +1069,20 @@ fragend_add_layer_cb (CoglPipelineLayer *layer,
return TRUE;
}
typedef struct
{
CoglFramebuffer *framebuffer;
const CoglPipelineVertend *vertend;
CoglPipeline *pipeline;
unsigned long *layer_differences;
CoglBool error_adding_layer;
CoglBool added_layer;
} CoglPipelineVertendAddLayerState;
static CoglBool
vertend_add_layer_cb (CoglPipelineLayer *layer,
fragend_add_layer_cb (CoglPipelineLayer *layer,
void *user_data)
{
CoglPipelineVertendAddLayerState *state = user_data;
const CoglPipelineVertend *vertend = state->vertend;
CoglPipelineAddLayerState *state = user_data;
const CoglPipelineFragend *fragend = state->fragend;
CoglPipeline *pipeline = state->pipeline;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
/* Either enerate per layer code snippets or setup the
* fixed function matrix uniforms for each layer... */
if (G_LIKELY (vertend->add_layer (pipeline,
/* Either generate per layer code snippets or setup the
* fixed function glTexEnv for each layer... */
if (G_LIKELY (fragend->add_layer (pipeline,
layer,
state->layer_differences[unit_index],
state->framebuffer)))
state->layer_differences[unit_index])))
state->added_layer = TRUE;
else
{
@ -1159,11 +1149,12 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
CoglBool skip_gl_color,
int n_tex_coord_attribs)
{
unsigned long pipelines_difference;
int n_layers;
unsigned long *layer_differences;
int i;
unsigned long pipelines_difference;
int n_layers;
unsigned long *layer_differences;
int i;
CoglTextureUnit *unit1;
const CoglPipelineProgend *progend;
COGL_STATIC_TIMER (pipeline_flush_timer,
"Mainloop", /* parent */
@ -1242,88 +1233,40 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
layer_differences,
skip_gl_color);
/* Now flush the fragment processing state according to the current
* fragment processing backend.
/* Now flush the fragment, vertex and program state according to the
* current progend backend.
*
* Note: Some of the backends may not support the current pipeline
* configuration and in that case it will report an error and we
* will fallback to a different backend.
* Note: Some backends may not support the current pipeline
* configuration and in that case it will report and error and we
* will look for a different backend.
*
* NB: if pipeline->backend != COGL_PIPELINE_FRAGEND_UNDEFINED then
* NB: if pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED then
* we have previously managed to successfully flush this pipeline
* with the given backend so we will simply use that to avoid
* with the given progend so we will simply use that to avoid
* fallback code paths.
*/
if (pipeline->progend == COGL_PIPELINE_PROGEND_UNDEFINED)
_cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_DEFAULT);
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_UNDEFINED)
_cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
for (i = pipeline->fragend;
i < G_N_ELEMENTS (_cogl_pipeline_fragends);
i++, _cogl_pipeline_set_fragend (pipeline, i))
for (i = pipeline->progend;
i < COGL_PIPELINE_N_PROGENDS;
i++, _cogl_pipeline_set_progend (pipeline, i))
{
const CoglPipelineFragend *fragend = _cogl_pipeline_fragends[i];
CoglPipelineFragendAddLayerState state;
const CoglPipelineVertend *vertend;
const CoglPipelineFragend *fragend;
CoglPipelineAddLayerState state;
/* E.g. For fragends generating code they can setup their
* scratch buffers here... */
if (G_UNLIKELY (!fragend->start (pipeline,
n_layers,
pipelines_difference,
n_tex_coord_attribs)))
progend = _cogl_pipeline_progends[i];
if (G_UNLIKELY (!progend->start (pipeline)))
continue;
state.fragend = fragend;
state.pipeline = pipeline;
state.layer_differences = layer_differences;
state.error_adding_layer = FALSE;
state.added_layer = FALSE;
_cogl_pipeline_foreach_layer_internal (pipeline,
fragend_add_layer_cb,
&state);
vertend = _cogl_pipeline_vertends[progend->vertend];
if (G_UNLIKELY (state.error_adding_layer))
continue;
if (!state.added_layer &&
fragend->passthrough &&
G_UNLIKELY (!fragend->passthrough (pipeline)))
continue;
/* For fragends generating code they may compile and link their
* programs here, update any uniforms and tell OpenGL to use
* that program.
*/
if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference)))
continue;
break;
}
if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_fragends)))
g_warning ("No usable pipeline fragment backend was found!");
/* Now flush the vertex processing state according to the current
* vertex processing backend.
*/
if (pipeline->vertend == COGL_PIPELINE_VERTEND_UNDEFINED)
_cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
for (i = pipeline->vertend;
i < G_N_ELEMENTS (_cogl_pipeline_vertends);
i++, _cogl_pipeline_set_vertend (pipeline, i))
{
const CoglPipelineVertend *vertend = _cogl_pipeline_vertends[i];
CoglPipelineVertendAddLayerState state;
/* E.g. For vertends generating code they can setup their
* scratch buffers here... */
if (G_UNLIKELY (!vertend->start (pipeline,
n_layers,
pipelines_difference,
n_tex_coord_attribs)))
continue;
vertend->start (pipeline,
n_layers,
pipelines_difference,
n_tex_coord_attribs);
state.framebuffer = framebuffer;
state.vertend = vertend;
@ -1331,6 +1274,7 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
state.layer_differences = layer_differences;
state.error_adding_layer = FALSE;
state.added_layer = FALSE;
_cogl_pipeline_foreach_layer_internal (pipeline,
vertend_add_layer_cb,
&state);
@ -1338,24 +1282,46 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
if (G_UNLIKELY (state.error_adding_layer))
continue;
/* For vertends generating code they may compile and link their
* programs here, update any uniforms and tell OpenGL to use
* that program.
*/
if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference)))
continue;
/* Now prepare the fragment processing state (fragend)
*
* NB: We can't combine the setup of the vertend and fragend
* since the backends that do code generation share
* ctx->codegen_source_buffer as a scratch buffer.
*/
fragend = _cogl_pipeline_fragends[progend->fragend];
state.fragend = fragend;
fragend->start (pipeline,
n_layers,
pipelines_difference,
n_tex_coord_attribs);
_cogl_pipeline_foreach_layer_internal (pipeline,
fragend_add_layer_cb,
&state);
if (G_UNLIKELY (state.error_adding_layer))
continue;
if (!state.added_layer)
{
if (fragend->passthrough &&
G_UNLIKELY (!fragend->passthrough (pipeline)))
continue;
}
if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference)))
continue;
if (progend->end)
progend->end (pipeline, pipelines_difference, n_tex_coord_attribs);
break;
}
if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_vertends)))
g_warning ("No usable pipeline vertex backend was found!");
for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
if (_cogl_pipeline_progends[i]->end)
_cogl_pipeline_progends[i]->end (pipeline, pipelines_difference,
n_tex_coord_attribs);
/* FIXME: This reference is actually resulting in lots of
* copy-on-write reparenting because one-shot pipelines end up
* living for longer than necessary and so any later modification of
@ -1374,6 +1340,8 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
done:
progend = _cogl_pipeline_progends[pipeline->progend];
/* We can't assume the color will be retained between flushes on
GLES2 because the generic attribute values are not stored as part
of the program object so they could be overridden by any
@ -1398,12 +1366,11 @@ done:
}
#endif
/* Give any progends a chance to update any uniforms that might not
depend on the material state. This is used on GLES2 to update the
matrices */
for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
if (_cogl_pipeline_progends[i]->pre_paint)
_cogl_pipeline_progends[i]->pre_paint (pipeline, framebuffer);
/* Give the progend a chance to update any uniforms that might not
* depend on the material state. This is used on GLES2 to update the
* matrices */
if (progend->pre_paint)
progend->pre_paint (pipeline, framebuffer);
/* Handle the fact that OpenGL associates texture filter and wrap
* modes with the texture objects not the texture units... */

View file

@ -32,6 +32,7 @@
#include <string.h>
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-state-private.h"
#ifdef COGL_PIPELINE_PROGEND_FIXED
@ -39,15 +40,39 @@
#include "cogl-context-private.h"
#include "cogl-framebuffer-private.h"
static CoglBool
_cogl_pipeline_progend_fixed_start (CoglPipeline *pipeline)
{
_COGL_GET_CONTEXT (ctx, FALSE);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
return FALSE;
if (ctx->driver == COGL_DRIVER_GLES2)
return FALSE;
/* Vertex snippets are only supported in the GLSL fragend */
if (_cogl_pipeline_has_vertex_snippets (pipeline))
return FALSE;
/* Fragment snippets are only supported in the GLSL fragend */
if (_cogl_pipeline_has_fragment_snippets (pipeline))
return FALSE;
/* If there is a user program then the appropriate backend for that
* language should handle it. */
if (cogl_pipeline_get_user_program (pipeline))
return FALSE;
return TRUE;
}
static void
_cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer)
{
CoglContext *ctx = framebuffer->context;
if (pipeline->vertend != COGL_PIPELINE_VERTEND_FIXED)
return;
if (ctx->current_projection_entry)
_cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_projection_entry,
@ -64,6 +89,9 @@ _cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline,
const CoglPipelineProgend _cogl_pipeline_fixed_progend =
{
COGL_PIPELINE_VERTEND_FIXED,
COGL_PIPELINE_FRAGEND_FIXED,
_cogl_pipeline_progend_fixed_start,
NULL, /* end */
NULL, /* pre_change_notify */
NULL, /* layer_pre_change_notify */

View file

@ -645,6 +645,24 @@ _cogl_pipeline_progend_glsl_flush_uniforms (CoglPipeline *pipeline,
_cogl_bitmask_clear_all (&uniforms_state->changed_mask);
}
static CoglBool
_cogl_pipeline_progend_glsl_start (CoglPipeline *pipeline)
{
CoglHandle user_program;
_COGL_GET_CONTEXT (ctx, FALSE);
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
return FALSE;
user_program = cogl_pipeline_get_user_program (pipeline);
if (user_program &&
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
return FALSE;
return TRUE;
}
static void
_cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
unsigned long pipelines_difference,
@ -659,12 +677,6 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* If neither of the glsl fragend or vertends are used then we don't
need to do anything */
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_GLSL &&
pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
return;
program_state = get_program_state (pipeline);
user_program = cogl_pipeline_get_user_program (pipeline);
@ -763,11 +775,9 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
}
/* Attach any shaders from the GLSL backends */
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL &&
(backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
if ((backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
GE( ctx, glAttachShader (program_state->program, backend_shader) );
if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL &&
(backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
if ((backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
GE( ctx, glAttachShader (program_state->program, backend_shader) );
link_program (program_state->program);
@ -779,10 +789,8 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
gl_program = program_state->program;
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL)
_cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL)
_cogl_use_vertex_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
_cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
_cogl_use_vertex_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
state.unit = 0;
state.gl_program = gl_program;
@ -939,9 +947,6 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
return;
program_state = get_program_state (pipeline);
projection_entry = ctx->current_projection_entry;
@ -1099,6 +1104,9 @@ update_float_uniform (CoglPipeline *pipeline,
const CoglPipelineProgend _cogl_pipeline_glsl_progend =
{
COGL_PIPELINE_VERTEND_GLSL,
COGL_PIPELINE_FRAGEND_GLSL,
_cogl_pipeline_progend_glsl_start,
_cogl_pipeline_progend_glsl_end,
_cogl_pipeline_progend_glsl_pre_change_notify,
_cogl_pipeline_progend_glsl_layer_pre_change_notify,

View file

@ -44,38 +44,13 @@
const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
static CoglBool
static void
_cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglProgram *user_program;
_COGL_GET_CONTEXT (ctx, FALSE);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
return FALSE;
if (ctx->driver == COGL_DRIVER_GLES2)
return FALSE;
/* Vertex snippets are only supported in the GLSL fragend */
if (_cogl_pipeline_has_vertex_snippets (pipeline))
return FALSE;
/* If there is a user program with a vertex shader then the
appropriate backend for that language should handle it. We can
still use the fixed vertex backend if the program only contains
a fragment shader */
user_program = cogl_pipeline_get_user_program (pipeline);
if (user_program != COGL_INVALID_HANDLE &&
_cogl_program_has_vertex_shader (user_program))
return FALSE;
_cogl_use_vertex_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
return TRUE;
}
static CoglBool

View file

@ -149,7 +149,7 @@ get_layer_vertex_snippets (CoglPipelineLayer *layer)
return &layer->big_state->vertex_snippets;
}
static CoglBool
static void
_cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
@ -157,21 +157,9 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
{
CoglPipelineShaderState *shader_state;
CoglPipeline *template_pipeline = NULL;
CoglProgram *user_program;
CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
_COGL_GET_CONTEXT (ctx, FALSE);
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
return FALSE;
user_program = cogl_pipeline_get_user_program (pipeline);
/* If the user program has a vertex shader that isn't GLSL then the
appropriate vertend for that language should handle it */
if (user_program &&
_cogl_program_has_vertex_shader (user_program) &&
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
return FALSE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Now lookup our glsl backend private state (allocating if
* necessary) */
@ -238,7 +226,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
shader_state->user_program_age == user_program->age)
&& (ctx->driver != COGL_DRIVER_GLES2 ||
shader_state->n_tex_coord_attribs == n_tex_coord_attribs))
return TRUE;
return;
/* We need to recreate the shader so destroy the existing one */
GE( ctx, glDeleteShader (shader_state->gl_shader) );
@ -258,7 +246,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
to generate one */
if (user_program &&
_cogl_program_has_vertex_shader (user_program))
return TRUE;
return;
/* We reuse two grow-only GStrings for code-gen. One string
contains the uniform and attribute declarations while the
@ -280,8 +268,6 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
to copy it from the custom uniform in the vertex shader */
g_string_append (shader_state->source,
" cogl_point_size_out = cogl_point_size_in;\n");
return TRUE;
}
static CoglBool

View file

@ -155,7 +155,7 @@ dirty_shader_state (CoglPipeline *pipeline)
NULL);
}
static CoglBool
static void
_cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
@ -164,38 +164,9 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
CoglPipelineShaderState *shader_state;
CoglPipeline *authority;
CoglPipeline *template_pipeline = NULL;
CoglHandle user_program;
CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
_COGL_GET_CONTEXT (ctx, FALSE);
/* First validate that we can handle the current state using ARBfp
*/
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP))
return FALSE;
/* TODO: support fog */
if (_cogl_pipeline_get_fog_enabled (pipeline))
return FALSE;
/* Fragment snippets are only supported in the GLSL fragend */
if (_cogl_pipeline_has_fragment_snippets (pipeline))
return FALSE;
user_program = cogl_pipeline_get_user_program (pipeline);
if (user_program != COGL_INVALID_HANDLE)
{
/* If the program doesn't have a fragment shader then some other
vertend will handle the vertex shader state and we still need
to generate a fragment program */
if (!_cogl_program_has_fragment_shader (user_program))
user_program = COGL_INVALID_HANDLE;
/* If the user program does have a fragment shader then we can
only handle it if it's in ARBfp */
else if (_cogl_program_get_language (user_program) !=
COGL_SHADER_LANGUAGE_ARBFP)
return FALSE;
}
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Now lookup our ARBfp backend private state */
shader_state = get_shader_state (pipeline);
@ -203,7 +174,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
/* If we have a valid shader_state then we are all set and don't
* need to generate a new program. */
if (shader_state)
return TRUE;
return;
/* If we don't have an associated arbfp program yet then find the
* arbfp-authority (the oldest ancestor whose state will result in
@ -226,7 +197,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
* arbfp-authority... */
shader_state->ref_count++;
set_shader_state (pipeline, shader_state);
return TRUE;
return;
}
/* If we haven't yet found an existing program then before we resort to
@ -285,8 +256,6 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
shader_state->ref_count++;
set_shader_state (template_pipeline, shader_state);
}
return TRUE;
}
static const char *

View file

@ -0,0 +1,36 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#ifndef __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H
#define __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H
#include "cogl-pipeline-private.h"
extern const CoglPipelineProgend _cogl_pipeline_fixed_arbfp_progend;
#endif /* __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H */

View file

@ -0,0 +1,110 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2012 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
*
* Authors:
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-state-private.h"
#ifdef COGL_PIPELINE_PROGEND_FIXED_ARBFP
#include "cogl-context.h"
#include "cogl-context-private.h"
#include "cogl-framebuffer-private.h"
#include "cogl-program-private.h"
static CoglBool
_cogl_pipeline_progend_fixed_arbfp_start (CoglPipeline *pipeline)
{
CoglHandle user_program;
_COGL_GET_CONTEXT (ctx, FALSE);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
return FALSE;
if (ctx->driver == COGL_DRIVER_GLES2)
return FALSE;
/* Vertex snippets are only supported in the GLSL fragend */
if (_cogl_pipeline_has_vertex_snippets (pipeline))
return FALSE;
/* Validate that we can handle the fragment state using ARBfp
*/
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP))
return FALSE;
/* Fragment snippets are only supported in the GLSL fragend */
if (_cogl_pipeline_has_fragment_snippets (pipeline))
return FALSE;
user_program = cogl_pipeline_get_user_program (pipeline);
if (user_program &&
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_ARBFP)
return FALSE;
return TRUE;
}
static void
_cogl_pipeline_progend_fixed_arbfp_pre_paint (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer)
{
CoglContext *ctx = framebuffer->context;
if (ctx->current_projection_entry)
_cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_projection_entry,
COGL_MATRIX_PROJECTION,
framebuffer,
FALSE /* enable flip */);
if (ctx->current_modelview_entry)
_cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_modelview_entry,
COGL_MATRIX_MODELVIEW,
framebuffer,
FALSE /* enable flip */);
}
const CoglPipelineProgend _cogl_pipeline_fixed_arbfp_progend =
{
COGL_PIPELINE_VERTEND_FIXED,
COGL_PIPELINE_FRAGEND_ARBFP,
_cogl_pipeline_progend_fixed_arbfp_start,
NULL, /* end */
NULL, /* pre_change_notify */
NULL, /* layer_pre_change_notify */
_cogl_pipeline_progend_fixed_arbfp_pre_paint
};
#endif /* COGL_PIPELINE_PROGEND_FIXED_ARBFP */