cogl: Add a fixed function vertend

The vertends are intended to flush state that would be represented in
a vertex program. Code to handle the layer matrix, lighting and
point size has now been moved from the common cogl-pipeline-opengl
backend to the fixed vertend.
This commit is contained in:
Neil Roberts 2010-11-29 18:32:21 +00:00
parent 9b1ab9f0ec
commit 3cf9159769
6 changed files with 342 additions and 33 deletions

View File

@ -240,6 +240,8 @@ cogl_sources_c = \
$(srcdir)/cogl-pipeline-fragend-arbfp-private.h \
$(srcdir)/cogl-pipeline-fragend-fixed.c \
$(srcdir)/cogl-pipeline-fragend-fixed-private.h \
$(srcdir)/cogl-pipeline-vertend-fixed.c \
$(srcdir)/cogl-pipeline-vertend-fixed-private.h \
$(srcdir)/cogl-pipeline-progend-glsl.c \
$(srcdir)/cogl-pipeline-progend-glsl-private.h \
$(srcdir)/cogl-material-compat.c \

View File

@ -421,21 +421,6 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
}
}
if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
{
CoglPipeline *authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
CoglPipelineLightingState *lighting_state =
&authority->big_state->lighting_state;
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, lighting_state->ambient));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, lighting_state->diffuse));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, lighting_state->specular));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, lighting_state->emission));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
&lighting_state->shininess));
}
if (pipelines_difference & COGL_PIPELINE_STATE_BLEND)
{
CoglPipeline *authority =
@ -678,18 +663,6 @@ flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data)
unit->texture_storage_changed = FALSE;
}
if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
{
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, state);
_cogl_matrix_stack_set (unit->matrix_stack,
&authority->big_state->matrix);
_cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
}
/* Under GLES2 the fragment shader will use gl_PointCoord instead of
replacing the texture coordinates */
#ifndef HAVE_COGL_GLES2
@ -905,6 +878,42 @@ fragend_add_layer_cb (CoglPipelineLayer *layer,
return TRUE;
}
typedef struct
{
const CoglPipelineVertend *vertend;
CoglPipeline *pipeline;
unsigned long *layer_differences;
gboolean error_adding_layer;
gboolean added_layer;
} CoglPipelineVertendAddLayerState;
static gboolean
vertend_add_layer_cb (CoglPipelineLayer *layer,
void *user_data)
{
CoglPipelineVertendAddLayerState *state = user_data;
const CoglPipelineVertend *vertend = state->vertend;
CoglPipeline *pipeline = state->pipeline;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
_COGL_GET_CONTEXT (ctx, FALSE);
/* Either enerate per layer code snippets or setup the
* fixed function matrix uniforms for each layer... */
if (G_LIKELY (vertend->add_layer (pipeline,
layer,
state->layer_differences[unit_index])))
state->added_layer = TRUE;
else
{
state->error_adding_layer = TRUE;
return FALSE;
}
return TRUE;
}
/*
* _cogl_pipeline_flush_gl_state:
*
@ -1094,6 +1103,52 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
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)))
continue;
state.vertend = vertend;
state.pipeline = 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);
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;
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,

View File

@ -71,6 +71,13 @@ typedef struct _CoglPipelineLayer CoglPipelineLayer;
#define COGL_PIPELINE_FRAGEND_DEFAULT 0
#define COGL_PIPELINE_FRAGEND_UNDEFINED 3
#define COGL_PIPELINE_VERTEND_FIXED 0
#define COGL_PIPELINE_N_VERTENDS 1
#define COGL_PIPELINE_VERTEND_DEFAULT 0
#define COGL_PIPELINE_VERTEND_UNDEFINED 3
/* If we have either of the GLSL backends then we also need a GLSL
progend to combine the shaders generated into a single
program. Currently there is only one progend but if we ever add
@ -610,7 +617,7 @@ struct _CoglPipeline
* state with the ancestors of other pipelines and those ancestors
* could currently be associated with different backends.
*
* Each set bit indicates if the correspondong ->backend_privs[]
* Each set bit indicates if the corresponding ->fragend_privs[]
* entry is valid.
*/
unsigned int fragend_priv_set_mask:COGL_PIPELINE_N_FRAGENDS;
@ -648,6 +655,7 @@ struct _CoglPipeline
* the pipeline and any private state the backend has associated
* with the pipeline. */
unsigned int fragend:3;
unsigned int vertend:3;
};
typedef struct _CoglPipelineFragend
@ -674,6 +682,25 @@ typedef struct _CoglPipelineFragend
void (*free_priv) (CoglPipeline *pipeline);
} CoglPipelineFragend;
typedef struct _CoglPipelineVertend
{
gboolean (*start) (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference);
gboolean (*add_layer) (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference);
gboolean (*end) (CoglPipeline *pipeline,
unsigned long pipelines_difference);
void (*pipeline_pre_change_notify) (CoglPipeline *pipeline,
CoglPipelineState change,
const CoglColor *new_color);
void (*layer_pre_change_notify) (CoglPipeline *owner,
CoglPipelineLayer *layer,
CoglPipelineLayerState change);
} CoglPipelineVertend;
typedef struct
{
void (*end) (CoglPipeline *pipeline,
@ -696,6 +723,8 @@ typedef enum
extern const CoglPipelineFragend *
_cogl_pipeline_fragends[COGL_PIPELINE_N_FRAGENDS];
extern const CoglPipelineVertend *
_cogl_pipeline_vertends[COGL_PIPELINE_N_VERTENDS];
extern const CoglPipelineProgend *
_cogl_pipeline_progends[];
@ -933,6 +962,9 @@ _cogl_pipeline_weak_copy (CoglPipeline *pipeline,
void
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend);
void
_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend);
CoglPipeline *
_cogl_pipeline_get_parent (CoglPipeline *pipeline);

View File

@ -0,0 +1,36 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2010 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_VERTEND_FIXED_PRIVATE_H
#define __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H
#include "cogl-pipeline-private.h"
extern const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
#endif /* __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H */

View File

@ -0,0 +1,114 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2008,2009,2010 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>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-opengl-private.h"
#ifdef COGL_PIPELINE_VERTEND_FIXED
#include "cogl.h"
#include "cogl-internal.h"
#include "cogl-context.h"
#include "cogl-handle.h"
const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
static gboolean
_cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference)
{
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_FIXED))
return FALSE;
return TRUE;
}
static gboolean
_cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference)
{
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index);
if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
{
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, state);
_cogl_matrix_stack_set (unit->matrix_stack,
&authority->big_state->matrix);
_cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
}
return TRUE;
}
static gboolean
_cogl_pipeline_vertend_fixed_end (CoglPipeline *pipeline,
unsigned long pipelines_difference)
{
if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
{
CoglPipeline *authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
CoglPipelineLightingState *lighting_state =
&authority->big_state->lighting_state;
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT,
lighting_state->ambient));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE,
lighting_state->diffuse));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
lighting_state->specular));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
lighting_state->emission));
GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
&lighting_state->shininess));
}
return TRUE;
}
const CoglPipelineVertend _cogl_pipeline_fixed_vertend =
{
_cogl_pipeline_vertend_fixed_start,
_cogl_pipeline_vertend_fixed_add_layer,
_cogl_pipeline_vertend_fixed_end,
NULL, /* pipeline_change_notify */
NULL /* layer_change_notify */
};
#endif /* COGL_PIPELINE_VERTEND_FIXED */

View File

@ -64,6 +64,7 @@ static void recursively_free_layer_caches (CoglPipeline *pipeline);
static gboolean _cogl_pipeline_is_weak (CoglPipeline *pipeline);
const CoglPipelineFragend *_cogl_pipeline_fragends[COGL_PIPELINE_N_FRAGENDS];
const CoglPipelineVertend *_cogl_pipeline_vertends[COGL_PIPELINE_N_VERTENDS];
/* The 'MAX' here is so that we don't define an empty array when there
are no progends */
const CoglPipelineProgend *
@ -82,6 +83,10 @@ _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)];
#include "cogl-pipeline-progend-glsl-private.h"
#endif
#ifdef COGL_PIPELINE_VERTEND_FIXED
#include "cogl-pipeline-vertend-fixed-private.h"
#endif
COGL_OBJECT_DEFINE (Pipeline, pipeline);
/* This type was made deprecated before the cogl_is_pipeline_layer
function was ever exposed in the public headers so there's no need
@ -224,11 +229,17 @@ _cogl_pipeline_init_default_pipeline (void)
&_cogl_pipeline_glsl_progend;
#endif
#ifdef COGL_PIPELINE_VERTEND_FIXED
_cogl_pipeline_vertends[COGL_PIPELINE_VERTEND_FIXED] =
&_cogl_pipeline_fixed_vertend;
#endif
_cogl_pipeline_node_init (COGL_PIPELINE_NODE (pipeline));
pipeline->is_weak = FALSE;
pipeline->journal_ref_count = 0;
pipeline->fragend = COGL_PIPELINE_FRAGEND_UNDEFINED;
pipeline->vertend = COGL_PIPELINE_VERTEND_UNDEFINED;
pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE;
pipeline->real_blend_enable = FALSE;
@ -356,9 +367,9 @@ _cogl_pipeline_set_parent (CoglPipeline *pipeline,
if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
recursively_free_layer_caches (pipeline);
/* If the fragment processing backend is also caching state along
* with the pipeline that depends on the pipeline's ancestry then it
* may be notified here...
/* If the backends are also caching state along with the 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)
@ -443,6 +454,8 @@ _cogl_pipeline_copy (CoglPipeline *src, gboolean is_weak)
pipeline->fragend = src->fragend;
pipeline->fragend_priv_set_mask = 0;
pipeline->vertend = src->vertend;
pipeline->has_static_breadcrumb = FALSE;
pipeline->age = 0;
@ -953,6 +966,12 @@ _cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend)
pipeline->fragend = fragend;
}
void
_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend)
{
pipeline->vertend = vertend;
}
static void
_cogl_pipeline_copy_differences (CoglPipeline *dest,
CoglPipeline *src,
@ -1184,13 +1203,45 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_FIXED)
_cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_UNDEFINED);
#endif
#ifdef COGL_PIPELINE_VERTEND_FIXED
if (pipeline->vertend == COGL_PIPELINE_VERTEND_FIXED)
_cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_UNDEFINED);
#endif
/* To simplify things for the backends we are careful about how
* we report STATE_LAYERS changes.
*
* All STATE_LAYERS changes 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 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.
*
* This just ensures backends only get a single pipeline or
* layer pre-change notification for any particular change.
*/
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
_cogl_pipeline_fragends[pipeline->fragend]->pipeline_pre_change_notify)
{
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[pipeline->fragend];
if (!from_layer_change)
fragend->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];
/* To simplify things for the backends we are careful about how
* we report STATE_LAYERS changes.
*
@ -1210,7 +1261,7 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
* layer pre-change notification for any particular change.
*/
if (!from_layer_change)
fragend->pipeline_pre_change_notify (pipeline, change, new_color);
vertend->pipeline_pre_change_notify (pipeline, change, new_color);
}
/* Notify all of the progends */
@ -1524,6 +1575,21 @@ _cogl_pipeline_fragend_layer_change_notify (CoglPipeline *owner,
}
}
static void
_cogl_pipeline_vertend_layer_change_notify (CoglPipeline *owner,
CoglPipelineLayer *layer,
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)
{
const CoglPipelineVertend *vertend =
_cogl_pipeline_vertends[owner->vertend];
vertend->layer_pre_change_notify (owner, layer, change);
}
}
static void
_cogl_pipeline_progend_layer_change_notify (CoglPipeline *owner,
CoglPipelineLayer *layer,
@ -1697,6 +1763,7 @@ _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
* dependant on this layer so it's ok to modify it. */
_cogl_pipeline_fragend_layer_change_notify (required_owner, layer, change);
_cogl_pipeline_vertend_layer_change_notify (required_owner, layer, change);
_cogl_pipeline_progend_layer_change_notify (required_owner, layer, change);
/* If the layer being changed is the same as the last layer we
@ -4356,7 +4423,10 @@ 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_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
* ancestors being the authority */