mirror of
https://github.com/brl/mutter.git
synced 2024-12-28 22:02:14 +00:00
db6c452aaa
As part of an on-going effort to get cogl-pipeline.c into a more maintainable state this splits out all the apis relating just to layer state. This just leaves code relating to the core CoglPipeline and CoglPipelineLayer design left in cogl-pipeline.c. This splits out around 2k more lines from cogl-pipeline.c although we are still left with nearly 4k lines so we still have some way to go! Reviewed-by: Neil Roberts <neil@linux.intel.com>
1665 lines
57 KiB
C
1665 lines
57 KiB
C
/*
|
|
* 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:
|
|
* Robert Bragg <robert@linux.intel.com>
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "cogl-pipeline-private.h"
|
|
#include "cogl-blend-string.h"
|
|
#include "cogl-util.h"
|
|
#include "cogl-matrix.h"
|
|
|
|
#include "string.h"
|
|
#if 0
|
|
#include "cogl-context-private.h"
|
|
#include "cogl-color-private.h"
|
|
|
|
#endif
|
|
|
|
/*
|
|
* XXX: consider special casing layer->unit_index so it's not a sparse
|
|
* property so instead we can assume it's valid for all layer
|
|
* instances.
|
|
* - We would need to initialize ->unit_index in
|
|
* _cogl_pipeline_layer_copy ().
|
|
*
|
|
* XXX: If you use this API you should consider that the given layer
|
|
* might not be writeable and so a new derived layer will be allocated
|
|
* and modified instead. The layer modified will be returned so you
|
|
* can identify when this happens.
|
|
*/
|
|
CoglPipelineLayer *
|
|
_cogl_pipeline_set_layer_unit (CoglPipeline *required_owner,
|
|
CoglPipelineLayer *layer,
|
|
int unit_index)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT;
|
|
CoglPipelineLayer *authority =
|
|
_cogl_pipeline_layer_get_authority (layer, change);
|
|
CoglPipelineLayer *new;
|
|
|
|
if (authority->unit_index == unit_index)
|
|
return layer;
|
|
|
|
new =
|
|
_cogl_pipeline_layer_pre_change_notify (required_owner,
|
|
layer,
|
|
change);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the layer we found is currently the authority on the state
|
|
* we are changing see if we can revert to one of our ancestors
|
|
* being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, change);
|
|
|
|
if (old_authority->unit_index == unit_index)
|
|
{
|
|
layer->differences &= ~change;
|
|
return layer;
|
|
}
|
|
}
|
|
}
|
|
|
|
layer->unit_index = unit_index;
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= change;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
|
|
return layer;
|
|
}
|
|
|
|
CoglHandle
|
|
_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer)
|
|
{
|
|
CoglPipelineLayer *authority =
|
|
_cogl_pipeline_layer_get_authority (layer,
|
|
COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
|
|
|
|
return authority->texture;
|
|
}
|
|
|
|
CoglHandle
|
|
_cogl_pipeline_get_layer_texture (CoglPipeline *pipeline,
|
|
int layer_index)
|
|
{
|
|
CoglPipelineLayer *layer =
|
|
_cogl_pipeline_get_layer (pipeline, layer_index);
|
|
return _cogl_pipeline_layer_get_texture (layer);
|
|
}
|
|
|
|
static void
|
|
_cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
GLenum target)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineLayer *new;
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
if (target == authority->target)
|
|
return;
|
|
|
|
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, change);
|
|
|
|
if (old_authority->target == target)
|
|
{
|
|
layer->differences &= ~change;
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
goto changed;
|
|
}
|
|
}
|
|
}
|
|
|
|
layer->target = target;
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= change;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
|
|
changed:
|
|
|
|
_cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
|
|
}
|
|
|
|
static void
|
|
_cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglHandle texture)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineLayer *new;
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
if (authority->texture == texture)
|
|
return;
|
|
|
|
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, change);
|
|
|
|
if (old_authority->texture == texture)
|
|
{
|
|
layer->differences &= ~change;
|
|
|
|
if (layer->texture != NULL)
|
|
cogl_object_unref (layer->texture);
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
goto changed;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (texture != NULL)
|
|
cogl_object_ref (texture);
|
|
if (layer == authority &&
|
|
layer->texture != NULL)
|
|
cogl_object_unref (layer->texture);
|
|
layer->texture = texture;
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= change;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
|
|
changed:
|
|
|
|
_cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
|
|
}
|
|
|
|
/* A convenience for querying the target of a given texture that
|
|
* notably returns 0 for NULL textures - so we can say that a layer
|
|
* with no associated CoglTexture will have a texture target of 0.
|
|
*/
|
|
static GLenum
|
|
get_texture_target (CoglHandle texture)
|
|
{
|
|
GLuint ignore_handle;
|
|
GLenum gl_target;
|
|
|
|
g_return_val_if_fail (texture, 0);
|
|
|
|
cogl_texture_get_gl_texture (texture, &ignore_handle, &gl_target);
|
|
|
|
return gl_target;
|
|
}
|
|
|
|
void
|
|
cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglHandle texture)
|
|
{
|
|
/* For the convenience of fragend code we separate texture state
|
|
* into the "target" and the "data", and setting a layer texture
|
|
* updates both of these properties.
|
|
*
|
|
* One example for why this is helpful is that the fragends may
|
|
* cache programs they generate and want to re-use those programs
|
|
* with all pipelines having equivalent fragment processing state.
|
|
* For the sake of determining if pipelines have equivalent fragment
|
|
* processing state we don't need to compare that the same
|
|
* underlying texture objects are referenced by the pipelines but we
|
|
* do need to see if they use the same texture targets. Making this
|
|
* distinction is much simpler if they are in different state
|
|
* groups.
|
|
*
|
|
* Note: if a NULL texture is set then we leave the target unchanged
|
|
* so we can avoid needlessly invalidating any associated fragment
|
|
* program.
|
|
*/
|
|
if (texture)
|
|
_cogl_pipeline_set_layer_texture_target (pipeline, layer_index,
|
|
get_texture_target (texture));
|
|
_cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture);
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_set_layer_wrap_modes (CoglPipeline *pipeline,
|
|
CoglPipelineLayer *layer,
|
|
CoglPipelineLayer *authority,
|
|
CoglPipelineWrapModeInternal wrap_mode_s,
|
|
CoglPipelineWrapModeInternal wrap_mode_t,
|
|
CoglPipelineWrapModeInternal wrap_mode_p)
|
|
{
|
|
CoglPipelineLayer *new;
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
|
|
if (authority->wrap_mode_s == wrap_mode_s &&
|
|
authority->wrap_mode_t == wrap_mode_t &&
|
|
authority->wrap_mode_p == wrap_mode_p)
|
|
return;
|
|
|
|
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, change);
|
|
|
|
if (old_authority->wrap_mode_s == wrap_mode_s &&
|
|
old_authority->wrap_mode_t == wrap_mode_t &&
|
|
old_authority->wrap_mode_p == wrap_mode_p)
|
|
{
|
|
layer->differences &= ~change;
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
layer->wrap_mode_s = wrap_mode_s;
|
|
layer->wrap_mode_t = wrap_mode_t;
|
|
layer->wrap_mode_p = wrap_mode_p;
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= change;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
}
|
|
|
|
static CoglPipelineWrapModeInternal
|
|
public_to_internal_wrap_mode (CoglPipelineWrapMode mode)
|
|
{
|
|
return (CoglPipelineWrapModeInternal)mode;
|
|
}
|
|
|
|
static CoglPipelineWrapMode
|
|
internal_to_public_wrap_mode (CoglPipelineWrapModeInternal internal_mode)
|
|
{
|
|
g_return_val_if_fail (internal_mode !=
|
|
COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_BORDER,
|
|
COGL_PIPELINE_WRAP_MODE_AUTOMATIC);
|
|
return (CoglPipelineWrapMode)internal_mode;
|
|
}
|
|
|
|
void
|
|
cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglPipelineWrapMode mode)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineWrapModeInternal internal_mode =
|
|
public_to_internal_wrap_mode (mode);
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
_cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
|
|
internal_mode,
|
|
authority->wrap_mode_t,
|
|
authority->wrap_mode_p);
|
|
}
|
|
|
|
void
|
|
cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglPipelineWrapMode mode)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineWrapModeInternal internal_mode =
|
|
public_to_internal_wrap_mode (mode);
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
_cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
|
|
authority->wrap_mode_s,
|
|
internal_mode,
|
|
authority->wrap_mode_p);
|
|
}
|
|
|
|
/* The rationale for naming the third texture coordinate 'p' instead
|
|
of OpenGL's usual 'r' is that 'r' conflicts with the usual naming
|
|
of the 'red' component when treating a vector as a color. Under
|
|
GLSL this is awkward because the texture swizzling for a vector
|
|
uses a single letter for each component and the names for colors,
|
|
textures and positions are synonymous. GLSL works around this by
|
|
naming the components of the texture s, t, p and q. Cogl already
|
|
effectively already exposes this naming because it exposes GLSL so
|
|
it makes sense to use that naming consistently. Another alternative
|
|
could be u, v and w. This is what Blender and Direct3D use. However
|
|
the w component conflicts with the w component of a position
|
|
vertex. */
|
|
void
|
|
cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglPipelineWrapMode mode)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineWrapModeInternal internal_mode =
|
|
public_to_internal_wrap_mode (mode);
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
_cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
|
|
authority->wrap_mode_s,
|
|
authority->wrap_mode_t,
|
|
internal_mode);
|
|
}
|
|
|
|
void
|
|
cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglPipelineWrapMode mode)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineWrapModeInternal internal_mode =
|
|
public_to_internal_wrap_mode (mode);
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
_cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
|
|
internal_mode,
|
|
internal_mode,
|
|
internal_mode);
|
|
/* XXX: I wonder if we should really be duplicating the mode into
|
|
* the 'r' wrap mode too? */
|
|
}
|
|
|
|
/* FIXME: deprecate this API */
|
|
CoglPipelineWrapMode
|
|
_cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
return internal_to_public_wrap_mode (authority->wrap_mode_s);
|
|
}
|
|
|
|
CoglPipelineWrapMode
|
|
cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index)
|
|
{
|
|
CoglPipelineLayer *layer;
|
|
|
|
g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
/* FIXME: we shouldn't ever construct a layer in a getter function */
|
|
|
|
return _cogl_pipeline_layer_get_wrap_mode_s (layer);
|
|
}
|
|
|
|
/* FIXME: deprecate this API */
|
|
CoglPipelineWrapMode
|
|
_cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
return internal_to_public_wrap_mode (authority->wrap_mode_t);
|
|
}
|
|
|
|
CoglPipelineWrapMode
|
|
cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index)
|
|
{
|
|
CoglPipelineLayer *layer;
|
|
|
|
g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
/* FIXME: we shouldn't ever construct a layer in a getter function */
|
|
|
|
return _cogl_pipeline_layer_get_wrap_mode_t (layer);
|
|
}
|
|
|
|
CoglPipelineWrapMode
|
|
_cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer)
|
|
{
|
|
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
|
|
CoglPipelineLayer *authority =
|
|
_cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
return internal_to_public_wrap_mode (authority->wrap_mode_p);
|
|
}
|
|
|
|
CoglPipelineWrapMode
|
|
cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index)
|
|
{
|
|
CoglPipelineLayer *layer;
|
|
|
|
g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
return _cogl_pipeline_layer_get_wrap_mode_p (layer);
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
|
|
CoglPipelineWrapModeInternal *wrap_mode_s,
|
|
CoglPipelineWrapModeInternal *wrap_mode_t,
|
|
CoglPipelineWrapModeInternal *wrap_mode_p)
|
|
{
|
|
CoglPipelineLayer *authority =
|
|
_cogl_pipeline_layer_get_authority (layer,
|
|
COGL_PIPELINE_LAYER_STATE_WRAP_MODES);
|
|
|
|
*wrap_mode_s = authority->wrap_mode_s;
|
|
*wrap_mode_t = authority->wrap_mode_t;
|
|
*wrap_mode_p = authority->wrap_mode_p;
|
|
}
|
|
|
|
gboolean
|
|
cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
gboolean enable,
|
|
GError **error)
|
|
{
|
|
CoglPipelineLayerState change =
|
|
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *new;
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
|
|
|
|
/* Don't allow point sprite coordinates to be enabled if the driver
|
|
doesn't support it */
|
|
if (enable && !cogl_features_available (COGL_FEATURE_POINT_SPRITE))
|
|
{
|
|
if (error)
|
|
{
|
|
g_set_error (error, COGL_ERROR, COGL_ERROR_UNSUPPORTED,
|
|
"Point sprite texture coordinates are enabled "
|
|
"for a layer but the GL driver does not support it.");
|
|
}
|
|
else
|
|
{
|
|
static gboolean warning_seen = FALSE;
|
|
if (!warning_seen)
|
|
g_warning ("Point sprite texture coordinates are enabled "
|
|
"for a layer but the GL driver does not support it.");
|
|
warning_seen = TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
if (authority->big_state->point_sprite_coords == enable)
|
|
return TRUE;
|
|
|
|
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, change);
|
|
|
|
if (old_authority->big_state->point_sprite_coords == enable)
|
|
{
|
|
layer->differences &= ~change;
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
layer->big_state->point_sprite_coords = enable;
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= change;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
|
|
int layer_index)
|
|
{
|
|
CoglPipelineLayerState change =
|
|
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
/* FIXME: we shouldn't ever construct a layer in a getter function */
|
|
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
|
|
return authority->big_state->point_sprite_coords;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1,
|
|
CoglPipelineEvalFlags flags)
|
|
{
|
|
return authority0->target == authority1->target;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1,
|
|
CoglPipelineEvalFlags flags)
|
|
{
|
|
GLuint gl_handle0, gl_handle1;
|
|
|
|
cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL);
|
|
cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL);
|
|
|
|
return gl_handle0 == gl_handle1;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1)
|
|
{
|
|
CoglPipelineLayerBigState *big_state0 = authority0->big_state;
|
|
CoglPipelineLayerBigState *big_state1 = authority1->big_state;
|
|
int n_args;
|
|
int i;
|
|
|
|
if (big_state0->texture_combine_rgb_func !=
|
|
big_state1->texture_combine_rgb_func)
|
|
return FALSE;
|
|
|
|
if (big_state0->texture_combine_alpha_func !=
|
|
big_state1->texture_combine_alpha_func)
|
|
return FALSE;
|
|
|
|
n_args =
|
|
_cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func);
|
|
for (i = 0; i < n_args; i++)
|
|
{
|
|
if ((big_state0->texture_combine_rgb_src[i] !=
|
|
big_state1->texture_combine_rgb_src[i]) ||
|
|
(big_state0->texture_combine_rgb_op[i] !=
|
|
big_state1->texture_combine_rgb_op[i]))
|
|
return FALSE;
|
|
}
|
|
|
|
n_args =
|
|
_cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func);
|
|
for (i = 0; i < n_args; i++)
|
|
{
|
|
if ((big_state0->texture_combine_alpha_src[i] !=
|
|
big_state1->texture_combine_alpha_src[i]) ||
|
|
(big_state0->texture_combine_alpha_op[i] !=
|
|
big_state1->texture_combine_alpha_op[i]))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1)
|
|
{
|
|
return memcmp (authority0->big_state->texture_combine_constant,
|
|
authority1->big_state->texture_combine_constant,
|
|
sizeof (float) * 4) == 0 ? TRUE : FALSE;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_filters_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1)
|
|
{
|
|
if (authority0->mag_filter != authority1->mag_filter)
|
|
return FALSE;
|
|
if (authority0->min_filter != authority1->min_filter)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
compare_wrap_mode_equal (CoglPipelineWrapMode wrap_mode0,
|
|
CoglPipelineWrapMode wrap_mode1)
|
|
{
|
|
/* We consider AUTOMATIC to be equivalent to CLAMP_TO_EDGE because
|
|
the primitives code is expected to override this to something
|
|
else if it wants it to be behave any other way */
|
|
if (wrap_mode0 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
|
|
wrap_mode0 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
|
|
if (wrap_mode1 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
|
|
wrap_mode1 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
|
|
|
|
return wrap_mode0 == wrap_mode1;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_wrap_modes_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1)
|
|
{
|
|
if (!compare_wrap_mode_equal (authority0->wrap_mode_s,
|
|
authority1->wrap_mode_s) ||
|
|
!compare_wrap_mode_equal (authority0->wrap_mode_t,
|
|
authority1->wrap_mode_t) ||
|
|
!compare_wrap_mode_equal (authority0->wrap_mode_p,
|
|
authority1->wrap_mode_p))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1)
|
|
{
|
|
CoglPipelineLayerBigState *big_state0 = authority0->big_state;
|
|
CoglPipelineLayerBigState *big_state1 = authority1->big_state;
|
|
|
|
if (!cogl_matrix_equal (&big_state0->matrix, &big_state1->matrix))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
|
|
CoglPipelineLayer *authority1)
|
|
{
|
|
CoglPipelineLayerBigState *big_state0 = authority0->big_state;
|
|
CoglPipelineLayerBigState *big_state1 = authority1->big_state;
|
|
|
|
return big_state0->point_sprite_coords == big_state1->point_sprite_coords;
|
|
}
|
|
|
|
static void
|
|
setup_texture_combine_state (CoglBlendStringStatement *statement,
|
|
CoglPipelineCombineFunc *texture_combine_func,
|
|
CoglPipelineCombineSource *texture_combine_src,
|
|
CoglPipelineCombineOp *texture_combine_op)
|
|
{
|
|
int i;
|
|
|
|
switch (statement->function->type)
|
|
{
|
|
case COGL_BLEND_STRING_FUNCTION_REPLACE:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE;
|
|
break;
|
|
case COGL_BLEND_STRING_FUNCTION_MODULATE:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE;
|
|
break;
|
|
case COGL_BLEND_STRING_FUNCTION_ADD:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD;
|
|
break;
|
|
case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED;
|
|
break;
|
|
case COGL_BLEND_STRING_FUNCTION_INTERPOLATE:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE;
|
|
break;
|
|
case COGL_BLEND_STRING_FUNCTION_SUBTRACT:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT;
|
|
break;
|
|
case COGL_BLEND_STRING_FUNCTION_DOT3_RGB:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB;
|
|
break;
|
|
case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA:
|
|
*texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA;
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < statement->function->argc; i++)
|
|
{
|
|
CoglBlendStringArgument *arg = &statement->args[i];
|
|
|
|
switch (arg->source.info->type)
|
|
{
|
|
case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT:
|
|
texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT;
|
|
break;
|
|
case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE:
|
|
texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
|
|
break;
|
|
case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N:
|
|
texture_combine_src[i] =
|
|
COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture;
|
|
break;
|
|
case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY:
|
|
texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR;
|
|
break;
|
|
case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS:
|
|
texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
|
|
break;
|
|
default:
|
|
g_warning ("Unexpected texture combine source");
|
|
texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
|
|
}
|
|
|
|
if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
|
|
{
|
|
if (statement->args[i].source.one_minus)
|
|
texture_combine_op[i] =
|
|
COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR;
|
|
else
|
|
texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
|
|
}
|
|
else
|
|
{
|
|
if (statement->args[i].source.one_minus)
|
|
texture_combine_op[i] =
|
|
COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA;
|
|
else
|
|
texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
|
|
}
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
const char *combine_description,
|
|
GError **error)
|
|
{
|
|
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineLayer *layer;
|
|
CoglBlendStringStatement statements[2];
|
|
CoglBlendStringStatement split[2];
|
|
CoglBlendStringStatement *rgb;
|
|
CoglBlendStringStatement *a;
|
|
GError *internal_error = NULL;
|
|
int count;
|
|
|
|
g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, state);
|
|
|
|
count =
|
|
_cogl_blend_string_compile (combine_description,
|
|
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE,
|
|
statements,
|
|
&internal_error);
|
|
if (!count)
|
|
{
|
|
if (error)
|
|
g_propagate_error (error, internal_error);
|
|
else
|
|
{
|
|
g_warning ("Cannot compile combine description: %s\n",
|
|
internal_error->message);
|
|
g_error_free (internal_error);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
|
|
{
|
|
_cogl_blend_string_split_rgba_statement (statements,
|
|
&split[0], &split[1]);
|
|
rgb = &split[0];
|
|
a = &split[1];
|
|
}
|
|
else
|
|
{
|
|
rgb = &statements[0];
|
|
a = &statements[1];
|
|
}
|
|
|
|
/* FIXME: compare the new state with the current state! */
|
|
|
|
/* possibly flush primitives referencing the current state... */
|
|
layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
|
|
|
|
setup_texture_combine_state (rgb,
|
|
&layer->big_state->texture_combine_rgb_func,
|
|
layer->big_state->texture_combine_rgb_src,
|
|
layer->big_state->texture_combine_rgb_op);
|
|
|
|
setup_texture_combine_state (a,
|
|
&layer->big_state->texture_combine_alpha_func,
|
|
layer->big_state->texture_combine_alpha_src,
|
|
layer->big_state->texture_combine_alpha_op);
|
|
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, state);
|
|
|
|
if (_cogl_pipeline_layer_combine_state_equal (authority,
|
|
old_authority))
|
|
{
|
|
layer->differences &= ~state;
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
goto changed;
|
|
}
|
|
}
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= state;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
|
|
changed:
|
|
|
|
_cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
const CoglColor *constant_color)
|
|
{
|
|
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineLayer *new;
|
|
float color_as_floats[4];
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, state);
|
|
|
|
color_as_floats[0] = cogl_color_get_red_float (constant_color);
|
|
color_as_floats[1] = cogl_color_get_green_float (constant_color);
|
|
color_as_floats[2] = cogl_color_get_blue_float (constant_color);
|
|
color_as_floats[3] = cogl_color_get_alpha_float (constant_color);
|
|
|
|
if (memcmp (authority->big_state->texture_combine_constant,
|
|
color_as_floats, sizeof (float) * 4) == 0)
|
|
return;
|
|
|
|
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, state);
|
|
CoglPipelineLayerBigState *old_big_state = old_authority->big_state;
|
|
|
|
if (memcmp (old_big_state->texture_combine_constant,
|
|
color_as_floats, sizeof (float) * 4) == 0)
|
|
{
|
|
layer->differences &= ~state;
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
goto changed;
|
|
}
|
|
}
|
|
}
|
|
|
|
memcpy (layer->big_state->texture_combine_constant,
|
|
color_as_floats,
|
|
sizeof (color_as_floats));
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= state;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
|
|
changed:
|
|
|
|
_cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
float *constant)
|
|
{
|
|
CoglPipelineLayerState change =
|
|
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
/* FIXME: we shouldn't ever construct a layer in a getter function */
|
|
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
memcpy (constant, authority->big_state->texture_combine_constant,
|
|
sizeof (float) * 4);
|
|
}
|
|
|
|
/* We should probably make a public API version of this that has a
|
|
matrix out-param. For an internal API it's good to be able to avoid
|
|
copying the matrix */
|
|
const CoglMatrix *
|
|
_cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index)
|
|
{
|
|
CoglPipelineLayerState change =
|
|
COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL);
|
|
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
authority = _cogl_pipeline_layer_get_authority (layer, change);
|
|
return &authority->big_state->matrix;
|
|
}
|
|
|
|
void
|
|
cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
const CoglMatrix *matrix)
|
|
{
|
|
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineLayer *new;
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, state);
|
|
|
|
if (cogl_matrix_equal (matrix, &authority->big_state->matrix))
|
|
return;
|
|
|
|
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, state);
|
|
|
|
if (cogl_matrix_equal (matrix, &old_authority->big_state->matrix))
|
|
{
|
|
layer->differences &= ~state;
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
layer->big_state->matrix = *matrix;
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= state;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
}
|
|
|
|
/* FIXME: deprecate and replace with
|
|
* cogl_pipeline_get_layer_texture() instead. */
|
|
CoglHandle
|
|
_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer)
|
|
{
|
|
g_return_val_if_fail (_cogl_is_pipeline_layer (layer), NULL);
|
|
|
|
return _cogl_pipeline_layer_get_texture_real (layer);
|
|
}
|
|
|
|
gboolean
|
|
_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
|
|
int layer_index)
|
|
{
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
authority =
|
|
_cogl_pipeline_layer_get_authority (layer,
|
|
COGL_PIPELINE_LAYER_STATE_USER_MATRIX);
|
|
|
|
/* If the authority is the default pipeline then no, otherwise yes */
|
|
return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE;
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
|
|
CoglPipelineFilter *min_filter,
|
|
CoglPipelineFilter *mag_filter)
|
|
{
|
|
CoglPipelineLayer *authority =
|
|
_cogl_pipeline_layer_get_authority (layer,
|
|
COGL_PIPELINE_LAYER_STATE_FILTERS);
|
|
|
|
*min_filter = authority->min_filter;
|
|
*mag_filter = authority->mag_filter;
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglPipelineFilter *min_filter,
|
|
CoglPipelineFilter *mag_filter)
|
|
{
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
authority =
|
|
_cogl_pipeline_layer_get_authority (layer,
|
|
COGL_PIPELINE_LAYER_STATE_FILTERS);
|
|
|
|
*min_filter = authority->min_filter;
|
|
*mag_filter = authority->mag_filter;
|
|
}
|
|
|
|
CoglPipelineFilter
|
|
_cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline,
|
|
int layer_index)
|
|
{
|
|
CoglPipelineFilter min_filter;
|
|
CoglPipelineFilter mag_filter;
|
|
|
|
_cogl_pipeline_get_layer_filters (pipeline, layer_index,
|
|
&min_filter, &mag_filter);
|
|
return min_filter;
|
|
}
|
|
|
|
CoglPipelineFilter
|
|
_cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
|
|
int layer_index)
|
|
{
|
|
CoglPipelineFilter min_filter;
|
|
CoglPipelineFilter mag_filter;
|
|
|
|
_cogl_pipeline_get_layer_filters (pipeline, layer_index,
|
|
&min_filter, &mag_filter);
|
|
return mag_filter;
|
|
}
|
|
|
|
CoglPipelineFilter
|
|
_cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer)
|
|
{
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
|
|
|
|
authority =
|
|
_cogl_pipeline_layer_get_authority (layer,
|
|
COGL_PIPELINE_LAYER_STATE_FILTERS);
|
|
|
|
return authority->min_filter;
|
|
}
|
|
|
|
CoglPipelineFilter
|
|
_cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer)
|
|
{
|
|
CoglPipelineLayer *authority;
|
|
|
|
g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
|
|
|
|
authority =
|
|
_cogl_pipeline_layer_get_authority (layer,
|
|
COGL_PIPELINE_LAYER_STATE_FILTERS);
|
|
|
|
return authority->mag_filter;
|
|
}
|
|
|
|
void
|
|
cogl_pipeline_set_layer_filters (CoglPipeline *pipeline,
|
|
int layer_index,
|
|
CoglPipelineFilter min_filter,
|
|
CoglPipelineFilter mag_filter)
|
|
{
|
|
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_FILTERS;
|
|
CoglPipelineLayer *layer;
|
|
CoglPipelineLayer *authority;
|
|
CoglPipelineLayer *new;
|
|
|
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
|
|
|
/* Note: this will ensure that the layer exists, creating one if it
|
|
* doesn't already.
|
|
*
|
|
* Note: If the layer already existed it's possibly owned by another
|
|
* pipeline. If the layer is created then it will be owned by
|
|
* pipeline. */
|
|
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
|
|
|
/* Now find the ancestor of the layer that is the authority for the
|
|
* state we want to change */
|
|
authority = _cogl_pipeline_layer_get_authority (layer, state);
|
|
|
|
if (authority->min_filter == min_filter &&
|
|
authority->mag_filter == mag_filter)
|
|
return;
|
|
|
|
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
|
|
if (new != layer)
|
|
layer = new;
|
|
else
|
|
{
|
|
/* If the original layer we found is currently the authority on
|
|
* the state we are changing see if we can revert to one of our
|
|
* ancestors being the authority. */
|
|
if (layer == authority &&
|
|
_cogl_pipeline_layer_get_parent (authority) != NULL)
|
|
{
|
|
CoglPipelineLayer *parent =
|
|
_cogl_pipeline_layer_get_parent (authority);
|
|
CoglPipelineLayer *old_authority =
|
|
_cogl_pipeline_layer_get_authority (parent, state);
|
|
|
|
if (old_authority->min_filter == min_filter &&
|
|
old_authority->mag_filter == mag_filter)
|
|
{
|
|
layer->differences &= ~state;
|
|
|
|
g_assert (layer->owner == pipeline);
|
|
if (layer->differences == 0)
|
|
_cogl_pipeline_prune_empty_layer_difference (pipeline,
|
|
layer);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
layer->min_filter = min_filter;
|
|
layer->mag_filter = mag_filter;
|
|
|
|
/* If we weren't previously the authority on this state then we need
|
|
* to extended our differences mask and so it's possible that some
|
|
* of our ancestry will now become redundant, so we aim to reparent
|
|
* ourselves if that's true... */
|
|
if (layer != authority)
|
|
{
|
|
layer->differences |= state;
|
|
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
|
|
}
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
int unit = authority->unit_index;
|
|
state->hash =
|
|
_cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit));
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
GLenum gl_target = authority->target;
|
|
|
|
state->hash =
|
|
_cogl_util_one_at_a_time_hash (state->hash, &gl_target, sizeof (gl_target));
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
GLuint gl_handle;
|
|
|
|
cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL);
|
|
|
|
state->hash =
|
|
_cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle));
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
unsigned int hash = state->hash;
|
|
hash = _cogl_util_one_at_a_time_hash (hash, &authority->mag_filter,
|
|
sizeof (authority->mag_filter));
|
|
hash = _cogl_util_one_at_a_time_hash (hash, &authority->min_filter,
|
|
sizeof (authority->min_filter));
|
|
state->hash = hash;
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
unsigned int hash = state->hash;
|
|
hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_s,
|
|
sizeof (authority->wrap_mode_s));
|
|
hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_t,
|
|
sizeof (authority->wrap_mode_t));
|
|
hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_p,
|
|
sizeof (authority->wrap_mode_p));
|
|
state->hash = hash;
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
unsigned int hash = state->hash;
|
|
CoglPipelineLayerBigState *b = authority->big_state;
|
|
int n_args;
|
|
int i;
|
|
|
|
hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_func,
|
|
sizeof (b->texture_combine_rgb_func));
|
|
n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
|
|
for (i = 0; i < n_args; i++)
|
|
{
|
|
hash =
|
|
_cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_src[i],
|
|
sizeof (b->texture_combine_rgb_src[i]));
|
|
hash =
|
|
_cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_op[i],
|
|
sizeof (b->texture_combine_rgb_op[i]));
|
|
}
|
|
|
|
hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_func,
|
|
sizeof (b->texture_combine_alpha_func));
|
|
n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
|
|
for (i = 0; i < n_args; i++)
|
|
{
|
|
hash =
|
|
_cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_src[i],
|
|
sizeof (b->texture_combine_alpha_src[i]));
|
|
hash =
|
|
_cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_op[i],
|
|
sizeof (b->texture_combine_alpha_op[i]));
|
|
}
|
|
|
|
state->hash = hash;
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
CoglPipelineLayerBigState *b = authority->big_state;
|
|
gboolean need_hash = FALSE;
|
|
int n_args;
|
|
int i;
|
|
|
|
/* XXX: If the user also asked to hash the ALPHA_FUNC_STATE then it
|
|
* would be nice if we could combine the n_args loops in this
|
|
* function and _cogl_pipeline_layer_hash_combine_state.
|
|
*/
|
|
|
|
n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
|
|
for (i = 0; i < n_args; i++)
|
|
{
|
|
if (b->texture_combine_rgb_src[i] ==
|
|
COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
|
|
{
|
|
/* XXX: should we be careful to only hash the alpha
|
|
* component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
|
|
need_hash = TRUE;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
|
|
for (i = 0; i < n_args; i++)
|
|
{
|
|
if (b->texture_combine_alpha_src[i] ==
|
|
COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
|
|
{
|
|
/* XXX: should we be careful to only hash the alpha
|
|
* component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
|
|
need_hash = TRUE;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (need_hash)
|
|
{
|
|
float *constant = b->texture_combine_constant;
|
|
state->hash = _cogl_util_one_at_a_time_hash (state->hash, constant,
|
|
sizeof (float) * 4);
|
|
}
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
CoglPipelineLayerBigState *big_state = authority->big_state;
|
|
state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix,
|
|
sizeof (float) * 16);
|
|
}
|
|
|
|
void
|
|
_cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
|
|
CoglPipelineLayer **authorities,
|
|
CoglPipelineHashState *state)
|
|
{
|
|
CoglPipelineLayerBigState *big_state = authority->big_state;
|
|
state->hash =
|
|
_cogl_util_one_at_a_time_hash (state->hash, &big_state->point_sprite_coords,
|
|
sizeof (big_state->point_sprite_coords));
|
|
}
|
|
|
|
|