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/cogl-pipeline-fragend-glsl-private.h \
$(srcdir)/driver/gl/gl/cogl-pipeline-fragend-arbfp.c \ $(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-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.c \
$(srcdir)/driver/gl/cogl-pipeline-fragend-fixed-private.h \ $(srcdir)/driver/gl/cogl-pipeline-fragend-fixed-private.h \
$(srcdir)/driver/gl/cogl-pipeline-vertend-glsl.c \ $(srcdir)/driver/gl/cogl-pipeline-vertend-glsl.c \

View File

@ -45,9 +45,10 @@
#ifdef HAVE_COGL_GL #ifdef HAVE_COGL_GL
#define COGL_PIPELINE_PROGEND_FIXED 0 #define COGL_PIPELINE_PROGEND_FIXED_ARBFP 0
#define COGL_PIPELINE_PROGEND_GLSL 1 #define COGL_PIPELINE_PROGEND_FIXED 1
#define COGL_PIPELINE_N_PROGENDS 2 #define COGL_PIPELINE_PROGEND_GLSL 2
#define COGL_PIPELINE_N_PROGENDS 3
#define COGL_PIPELINE_VERTEND_FIXED 0 #define COGL_PIPELINE_VERTEND_FIXED 0
#define COGL_PIPELINE_VERTEND_GLSL 1 #define COGL_PIPELINE_VERTEND_GLSL 1
@ -97,11 +98,8 @@
#endif /* HAVE_COGL_GL */ #endif /* HAVE_COGL_GL */
#define COGL_PIPELINE_FRAGEND_DEFAULT 0 #define COGL_PIPELINE_PROGEND_DEFAULT 0
#define COGL_PIPELINE_FRAGEND_UNDEFINED 3 #define COGL_PIPELINE_PROGEND_UNDEFINED 3
#define COGL_PIPELINE_VERTEND_DEFAULT 0
#define COGL_PIPELINE_VERTEND_UNDEFINED 3
/* XXX: should I rename these as /* XXX: should I rename these as
* COGL_PIPELINE_STATE_INDEX_XYZ... ? * COGL_PIPELINE_STATE_INDEX_XYZ... ?
@ -480,20 +478,19 @@ struct _CoglPipeline
* where the pipeline originates from */ * where the pipeline originates from */
unsigned int has_static_breadcrumb:1; unsigned int has_static_breadcrumb:1;
/* There are multiple fragment processing backends for CoglPipeline, /* There are multiple fragment and vertex processing backends for
* glsl, arbfp and fixed. This identifies the backend being used for * CoglPipeline, glsl, arbfp and fixed that are bundled under a
* the pipeline and any private state the backend has associated * "progend". This identifies the backend being used for the
* with the pipeline. */ * pipeline. */
unsigned int fragend:3; unsigned int progend:3;
unsigned int vertend:3;
}; };
typedef struct _CoglPipelineFragend typedef struct _CoglPipelineFragend
{ {
CoglBool (*start) (CoglPipeline *pipeline, void (*start) (CoglPipeline *pipeline,
int n_layers, int n_layers,
unsigned long pipelines_difference, unsigned long pipelines_difference,
int n_tex_coord_attribs); int n_tex_coord_attribs);
CoglBool (*add_layer) (CoglPipeline *pipeline, CoglBool (*add_layer) (CoglPipeline *pipeline,
CoglPipelineLayer *layer, CoglPipelineLayer *layer,
unsigned long layers_difference); unsigned long layers_difference);
@ -512,10 +509,10 @@ typedef struct _CoglPipelineFragend
typedef struct _CoglPipelineVertend typedef struct _CoglPipelineVertend
{ {
CoglBool (*start) (CoglPipeline *pipeline, void (*start) (CoglPipeline *pipeline,
int n_layers, int n_layers,
unsigned long pipelines_difference, unsigned long pipelines_difference,
int n_tex_coord_attribs); int n_tex_coord_attribs);
CoglBool (*add_layer) (CoglPipeline *pipeline, CoglBool (*add_layer) (CoglPipeline *pipeline,
CoglPipelineLayer *layer, CoglPipelineLayer *layer,
unsigned long layers_difference, unsigned long layers_difference,
@ -533,6 +530,9 @@ typedef struct _CoglPipelineVertend
typedef struct typedef struct
{ {
int vertend;
int fragend;
CoglBool (*start) (CoglPipeline *pipeline);
void (*end) (CoglPipeline *pipeline, void (*end) (CoglPipeline *pipeline,
unsigned long pipelines_difference, unsigned long pipelines_difference,
int n_tex_coord_attribs); int n_tex_coord_attribs);
@ -818,10 +818,7 @@ _cogl_pipeline_weak_copy (CoglPipeline *pipeline,
void *user_data); void *user_data);
void void
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend); _cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend);
void
_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend);
CoglPipeline * CoglPipeline *
_cogl_pipeline_get_parent (CoglPipeline *pipeline); _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); _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
if (program != COGL_INVALID_HANDLE) if (program != COGL_INVALID_HANDLE)
{ _cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_UNDEFINED);
_cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
_cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
}
/* If we are the current authority see if we can revert to one of our /* If we are the current authority see if we can revert to one of our
* ancestors being the authority */ * 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" #include "cogl-pipeline-vertend-fixed-private.h"
#endif #endif
#ifdef COGL_PIPELINE_PROGEND_FIXED_ARBFP
#include "cogl-pipeline-progend-fixed-arbfp-private.h"
#endif
#ifdef COGL_PIPELINE_PROGEND_FIXED #ifdef COGL_PIPELINE_PROGEND_FIXED
#include "cogl-pipeline-progend-fixed-private.h" #include "cogl-pipeline-progend-fixed-private.h"
#endif #endif
@ -125,6 +128,10 @@ _cogl_pipeline_init_default_pipeline (void)
_cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_FIXED] = _cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_FIXED] =
&_cogl_pipeline_fixed_fragend; &_cogl_pipeline_fixed_fragend;
#endif #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 #ifdef COGL_PIPELINE_PROGEND_FIXED
_cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED] = _cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED] =
&_cogl_pipeline_fixed_progend; &_cogl_pipeline_fixed_progend;
@ -147,8 +154,7 @@ _cogl_pipeline_init_default_pipeline (void)
pipeline->is_weak = FALSE; pipeline->is_weak = FALSE;
pipeline->journal_ref_count = 0; pipeline->journal_ref_count = 0;
pipeline->fragend = COGL_PIPELINE_FRAGEND_UNDEFINED; pipeline->progend = COGL_PIPELINE_PROGEND_UNDEFINED;
pipeline->vertend = COGL_PIPELINE_VERTEND_UNDEFINED;
pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE; pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE;
pipeline->real_blend_enable = FALSE; 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 * that depends on the pipeline's ancestry then it may be notified
* here... * here...
*/ */
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED && if (pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
_cogl_pipeline_fragends[pipeline->fragend]->pipeline_set_parent_notify)
{ {
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[pipeline->progend];
const CoglPipelineFragend *fragend = const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[pipeline->fragend]; _cogl_pipeline_fragends[progend->fragend];
fragend->pipeline_set_parent_notify (pipeline);
/* 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 = NULL;
pipeline->deprecated_get_layers_list_dirty = TRUE; pipeline->deprecated_get_layers_list_dirty = TRUE;
pipeline->fragend = src->fragend; pipeline->progend = src->progend;
pipeline->vertend = src->vertend;
pipeline->has_static_breadcrumb = FALSE; pipeline->has_static_breadcrumb = FALSE;
@ -831,15 +840,9 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline,
} }
void void
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend) _cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend)
{ {
pipeline->fragend = fragend; pipeline->progend = progend;
}
void
_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend)
{
pipeline->vertend = vertend;
} }
static void static void
@ -1191,46 +1194,37 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
* *
* All STATE_LAYERS change notification with the exception of * All STATE_LAYERS change notification with the exception of
* ->n_layers will also result in layer_pre_change_notifications. * ->n_layers will also result in layer_pre_change_notifications.
* For backends that perform code generation for fragment * For backends that perform code generation for fragment processing
* processing they typically need to understand the details of how * they typically need to understand the details of how layers get
* layers get changed to determine if they need to repeat codegen. * changed to determine if they need to repeat codegen. It doesn't
* It doesn't help them to * help them to report a pipeline STATE_LAYERS change for all layer
* report a pipeline STATE_LAYERS change for all layer changes since * changes since it's so broad, they really need to wait for the
* it's so broad, they really need to wait for the specific layer * specific layer change to be notified. What does help though is
* change to be notified. What does help though is to report a * to report a STATE_LAYERS change for a change in ->n_layers
* STATE_LAYERS change for a change in * because they typically do need to repeat codegen in that case.
* ->n_layers because they typically do need to repeat codegen in
* that case.
* *
* Here we ensure that change notifications against a pipeline or * Here we ensure that change notifications against a pipeline or
* against a layer are mutually exclusive as far as fragment, vertex * against a layer are mutually exclusive as far as fragment, vertex
* and program backends are concerned. * 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 && if (vertend->pipeline_pre_change_notify)
_cogl_pipeline_fragends[pipeline->fragend]->pipeline_pre_change_notify) vertend->pipeline_pre_change_notify (pipeline, change, new_color);
{
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[pipeline->fragend];
fragend->pipeline_pre_change_notify (pipeline, change, new_color);
}
if (pipeline->vertend != COGL_PIPELINE_VERTEND_UNDEFINED && if (fragend->pipeline_pre_change_notify)
_cogl_pipeline_vertends[pipeline->vertend]->pipeline_pre_change_notify) fragend->pipeline_pre_change_notify (pipeline, change, new_color);
{
const CoglPipelineVertend *vertend =
_cogl_pipeline_vertends[pipeline->vertend];
vertend->pipeline_pre_change_notify (pipeline, change, new_color);
}
for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++) if (progend->pipeline_pre_change_notify)
if (_cogl_pipeline_progends[i]->pipeline_pre_change_notify) progend->pipeline_pre_change_notify (pipeline, change, new_color);
_cogl_pipeline_progends[i]->pipeline_pre_change_notify (pipeline,
change,
new_color);
} }
/* There may be an arbitrary tree of descendants of this pipeline; /* 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 * have a single owner and can only be associated with a single
* backend that needs to be notified of the layer change... * backend that needs to be notified of the layer change...
*/ */
if (owner->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED && if (owner->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
_cogl_pipeline_fragends[owner->fragend]->layer_pre_change_notify)
{ {
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[owner->progend];
const CoglPipelineFragend *fragend = const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[owner->fragend]; _cogl_pipeline_fragends[progend->fragend];
fragend->layer_pre_change_notify (owner, layer, change);
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) CoglPipelineLayerState change)
{ {
/* NB: The comment in fragend_layer_change_notify applies here too */ /* NB: The comment in fragend_layer_change_notify applies here too */
if (owner->vertend != COGL_PIPELINE_VERTEND_UNDEFINED && if (owner->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
_cogl_pipeline_vertends[owner->vertend]->layer_pre_change_notify)
{ {
const CoglPipelineProgend *progend =
_cogl_pipeline_progends[owner->progend];
const CoglPipelineVertend *vertend = const CoglPipelineVertend *vertend =
_cogl_pipeline_vertends[owner->vertend]; _cogl_pipeline_vertends[progend->vertend];
vertend->layer_pre_change_notify (owner, layer, change);
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, CoglPipelineLayer *layer,
CoglPipelineLayerState change) 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 if (progend->layer_pre_change_notify)
changed */ progend->layer_pre_change_notify (owner, layer, change);
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);
} }
typedef struct typedef struct

View File

@ -89,37 +89,13 @@ get_max_texture_units (void)
return ctx->max_texture_units; return ctx->max_texture_units;
} }
static CoglBool static void
_cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline, _cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
int n_layers, int n_layers,
unsigned long pipelines_difference, unsigned long pipelines_difference,
int n_tex_coord_attribs) 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); _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
return TRUE;
} }
static void static void

View File

@ -213,7 +213,7 @@ has_replace_hook (CoglPipelineLayer *layer,
return FALSE; return FALSE;
} }
static CoglBool static void
_cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline, _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
int n_layers, int n_layers,
unsigned long pipelines_difference, unsigned long pipelines_difference,
@ -222,22 +222,10 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
CoglPipelineShaderState *shader_state; CoglPipelineShaderState *shader_state;
CoglPipeline *authority; CoglPipeline *authority;
CoglPipeline *template_pipeline = NULL; CoglPipeline *template_pipeline = NULL;
CoglProgram *user_program; CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
int i; int i;
_COGL_GET_CONTEXT (ctx, FALSE); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
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;
/* Now lookup our glsl backend private state */ /* Now lookup our glsl backend private state */
shader_state = get_shader_state (pipeline); 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) shader_state->user_program_age == user_program->age)
&& (ctx->driver != COGL_DRIVER_GLES2 || && (ctx->driver != COGL_DRIVER_GLES2 ||
shader_state->n_tex_coord_attribs == n_tex_coord_attribs)) shader_state->n_tex_coord_attribs == n_tex_coord_attribs))
return TRUE; return;
/* We need to recreate the shader so destroy the existing one */ /* We need to recreate the shader so destroy the existing one */
GE( ctx, glDeleteShader (shader_state->gl_shader) ); GE( ctx, glDeleteShader (shader_state->gl_shader) );
@ -333,7 +321,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
to generate one */ to generate one */
if (user_program && if (user_program &&
_cogl_program_has_fragment_shader (user_program)) _cogl_program_has_fragment_shader (user_program))
return TRUE; return;
/* We reuse two grow-only GStrings for code-gen. One string /* We reuse two grow-only GStrings for code-gen. One string
contains the uniform and attribute declarations while the 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].sampled = FALSE;
shader_state->unit_state[i].combine_constant_used = FALSE; shader_state->unit_state[i].combine_constant_used = FALSE;
} }
return TRUE;
} }
static void static void

View File

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

View File

@ -32,6 +32,7 @@
#include <string.h> #include <string.h>
#include "cogl-pipeline-private.h" #include "cogl-pipeline-private.h"
#include "cogl-pipeline-state-private.h"
#ifdef COGL_PIPELINE_PROGEND_FIXED #ifdef COGL_PIPELINE_PROGEND_FIXED
@ -39,15 +40,39 @@
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-framebuffer-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 static void
_cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline, _cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer) CoglFramebuffer *framebuffer)
{ {
CoglContext *ctx = framebuffer->context; CoglContext *ctx = framebuffer->context;
if (pipeline->vertend != COGL_PIPELINE_VERTEND_FIXED)
return;
if (ctx->current_projection_entry) if (ctx->current_projection_entry)
_cogl_matrix_entry_flush_to_gl_builtins (ctx, _cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_projection_entry, ctx->current_projection_entry,
@ -64,6 +89,9 @@ _cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline,
const CoglPipelineProgend _cogl_pipeline_fixed_progend = const CoglPipelineProgend _cogl_pipeline_fixed_progend =
{ {
COGL_PIPELINE_VERTEND_FIXED,
COGL_PIPELINE_FRAGEND_FIXED,
_cogl_pipeline_progend_fixed_start,
NULL, /* end */ NULL, /* end */
NULL, /* pre_change_notify */ NULL, /* pre_change_notify */
NULL, /* layer_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); _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 static void
_cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline, _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
unsigned long pipelines_difference, unsigned long pipelines_difference,
@ -659,12 +677,6 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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); program_state = get_program_state (pipeline);
user_program = cogl_pipeline_get_user_program (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 */ /* Attach any shaders from the GLSL backends */
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL && if ((backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
(backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
GE( ctx, glAttachShader (program_state->program, backend_shader) ); GE( ctx, glAttachShader (program_state->program, backend_shader) );
if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL && if ((backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
(backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
GE( ctx, glAttachShader (program_state->program, backend_shader) ); GE( ctx, glAttachShader (program_state->program, backend_shader) );
link_program (program_state->program); link_program (program_state->program);
@ -779,10 +789,8 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
gl_program = program_state->program; gl_program = program_state->program;
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL) _cogl_use_fragment_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);
if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL)
_cogl_use_vertex_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
state.unit = 0; state.unit = 0;
state.gl_program = gl_program; state.gl_program = gl_program;
@ -939,9 +947,6 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
return;
program_state = get_program_state (pipeline); program_state = get_program_state (pipeline);
projection_entry = ctx->current_projection_entry; projection_entry = ctx->current_projection_entry;
@ -1099,6 +1104,9 @@ update_float_uniform (CoglPipeline *pipeline,
const CoglPipelineProgend _cogl_pipeline_glsl_progend = 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_end,
_cogl_pipeline_progend_glsl_pre_change_notify, _cogl_pipeline_progend_glsl_pre_change_notify,
_cogl_pipeline_progend_glsl_layer_pre_change_notify, _cogl_pipeline_progend_glsl_layer_pre_change_notify,

View File

@ -44,38 +44,13 @@
const CoglPipelineVertend _cogl_pipeline_fixed_vertend; const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
static CoglBool static void
_cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline, _cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
int n_layers, int n_layers,
unsigned long pipelines_difference, unsigned long pipelines_difference,
int n_tex_coord_attribs) 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); _cogl_use_vertex_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
return TRUE;
} }
static CoglBool static CoglBool

View File

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

View File

@ -155,7 +155,7 @@ dirty_shader_state (CoglPipeline *pipeline)
NULL); NULL);
} }
static CoglBool static void
_cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline, _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
int n_layers, int n_layers,
unsigned long pipelines_difference, unsigned long pipelines_difference,
@ -164,38 +164,9 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
CoglPipelineShaderState *shader_state; CoglPipelineShaderState *shader_state;
CoglPipeline *authority; CoglPipeline *authority;
CoglPipeline *template_pipeline = NULL; CoglPipeline *template_pipeline = NULL;
CoglHandle user_program; CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
_COGL_GET_CONTEXT (ctx, FALSE); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* 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;
}
/* Now lookup our ARBfp backend private state */ /* Now lookup our ARBfp backend private state */
shader_state = get_shader_state (pipeline); 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 /* If we have a valid shader_state then we are all set and don't
* need to generate a new program. */ * need to generate a new program. */
if (shader_state) if (shader_state)
return TRUE; return;
/* If we don't have an associated arbfp program yet then find the /* If we don't have an associated arbfp program yet then find the
* arbfp-authority (the oldest ancestor whose state will result in * arbfp-authority (the oldest ancestor whose state will result in
@ -226,7 +197,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
* arbfp-authority... */ * arbfp-authority... */
shader_state->ref_count++; shader_state->ref_count++;
set_shader_state (pipeline, shader_state); set_shader_state (pipeline, shader_state);
return TRUE; return;
} }
/* If we haven't yet found an existing program then before we resort to /* 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++; shader_state->ref_count++;
set_shader_state (template_pipeline, shader_state); set_shader_state (template_pipeline, shader_state);
} }
return TRUE;
} }
static const char * 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 */