mutter/cogl/cogl-pipeline-state.c

2172 lines
70 KiB
C
Raw Normal View History

/*
* Cogl
*
This re-licenses Cogl 1.18 under the MIT license Since the Cogl 1.18 branch is actively maintained in parallel with the master branch; this is a counter part to commit 1b83ef938fc16b which re-licensed the master branch to use the MIT license. This re-licensing is a follow up to the proposal that was sent to the Cogl mailing list: http://lists.freedesktop.org/archives/cogl/2013-December/001465.html Note: there was a copyright assignment policy in place for Clutter (and therefore Cogl which was part of Clutter at the time) until the 11th of June 2010 and so we only checked the details after that point (commit 0bbf50f905) For each file, authors were identified via this Git command: $ git blame -p -C -C -C20 -M -M10 0bbf50f905..HEAD We received blanket approvals for re-licensing all Red Hat and Collabora contributions which reduced how many people needed to be contacted individually: - http://lists.freedesktop.org/archives/cogl/2013-December/001470.html - http://lists.freedesktop.org/archives/cogl/2014-January/001536.html Individual approval requests were sent to all the other identified authors who all confirmed the re-license on the Cogl mailinglist: http://lists.freedesktop.org/archives/cogl/2014-January As well as updating the copyright header in all sources files, the COPYING file has been updated to reflect the license change and also document the other licenses used in Cogl such as the SGI Free Software License B, version 2.0 and the 3-clause BSD license. This patch was not simply cherry-picked from master; but the same methodology was used to check the source files.
2014-02-22 01:28:54 +00:00
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2008,2009,2010 Intel Corporation.
*
This re-licenses Cogl 1.18 under the MIT license Since the Cogl 1.18 branch is actively maintained in parallel with the master branch; this is a counter part to commit 1b83ef938fc16b which re-licensed the master branch to use the MIT license. This re-licensing is a follow up to the proposal that was sent to the Cogl mailing list: http://lists.freedesktop.org/archives/cogl/2013-December/001465.html Note: there was a copyright assignment policy in place for Clutter (and therefore Cogl which was part of Clutter at the time) until the 11th of June 2010 and so we only checked the details after that point (commit 0bbf50f905) For each file, authors were identified via this Git command: $ git blame -p -C -C -C20 -M -M10 0bbf50f905..HEAD We received blanket approvals for re-licensing all Red Hat and Collabora contributions which reduced how many people needed to be contacted individually: - http://lists.freedesktop.org/archives/cogl/2013-December/001470.html - http://lists.freedesktop.org/archives/cogl/2014-January/001536.html Individual approval requests were sent to all the other identified authors who all confirmed the re-license on the Cogl mailinglist: http://lists.freedesktop.org/archives/cogl/2014-January As well as updating the copyright header in all sources files, the COPYING file has been updated to reflect the license change and also document the other licenses used in Cogl such as the SGI Free Software License B, version 2.0 and the 3-clause BSD license. This patch was not simply cherry-picked from master; but the same methodology was used to check the source files.
2014-02-22 01:28:54 +00:00
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*
* Authors:
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cogl-context-private.h"
#include "cogl-color-private.h"
#include "cogl-blend-string.h"
#include "cogl-util.h"
#include "cogl-depth-state-private.h"
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
#include "cogl-pipeline-state-private.h"
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
#include "cogl-snippet-private.h"
Adds CoglError api Although we use GLib internally in Cogl we would rather not leak GLib api through Cogl's own api, except through explicitly namespaced cogl_glib_ / cogl_gtype_ feature apis. One of the benefits we see to not leaking GLib through Cogl's public API is that documentation for Cogl won't need to first introduce the Glib API to newcomers, thus hopefully lowering the barrier to learning Cogl. This patch provides a Cogl specific typedef for reporting runtime errors which by no coincidence matches the typedef for GError exactly. If Cogl is built with --enable-glib (default) then developers can even safely assume that a CoglError is a GError under the hood. This patch also enforces a consistent policy for when NULL is passed as an error argument and an error is thrown. In this case we log the error and abort the application, instead of silently ignoring it. In common cases where nothing has been implemented to handle a particular error and/or where applications are just printing the error and aborting themselves then this saves some typing. This also seems more consistent with language based exceptions which usually cause a program to abort if they are not explicitly caught (which passing a non-NULL error signifies in this case) Since this policy for NULL error pointers is stricter than the standard GError convention, there is a clear note in the documentation to warn developers that are used to using the GError api. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit b068d5ea09ab32c37e8c965fc8582c85d1b2db46) Note: Since we can't change the Cogl 1.x api the patch was changed to not rename _error_quark() functions to be _error_domain() functions and although it's a bit ugly, instead of providing our own CoglError type that's compatible with GError we simply #define CoglError to GError unless Cogl is built with glib disabled. Note: this patch does technically introduce an API break since it drops the cogl_error_get_type() symbol generated by glib-mkenum (Since the CoglError enum was replaced by a CoglSystemError enum) but for now we are assuming that this will not affect anyone currently using the Cogl API. If this does turn out to be a problem in practice then we would be able to fix this my manually copying an implementation of cogl_error_get_type() generated by glib-mkenum into a compatibility source file and we could also define the original COGL_ERROR_ enums for compatibility too. Note: another minor concern with cherry-picking this patch to the 1.14 branch is that an api scanner would be lead to believe that some APIs have changed, and for example the gobject-introspection parser which understands the semantics of GError will not understand the semantics of CoglError. We expect most people that have tried to use gobject-introspection with Cogl already understand though that it is not well suited to generating bindings of the Cogl api anyway and we aren't aware or anyone depending on such bindings for apis involving GErrors. (GnomeShell only makes very-very minimal use of Cogl via the gjs bindings for the cogl_rectangle and cogl_color apis.) The main reason we have cherry-picked this patch to the 1.14 branch even given the above concerns is that without it it would become very awkward for us to cherry-pick other beneficial patches from master.
2012-08-31 18:28:27 +00:00
#include "cogl-error-private.h"
#include <test-fixtures/test-unit.h>
#include "string.h"
#ifndef GL_FUNC_ADD
#define GL_FUNC_ADD 0x8006
#endif
CoglPipeline *
_cogl_pipeline_get_user_program (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), NULL);
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER);
return authority->big_state->user_program;
}
CoglBool
_cogl_pipeline_color_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return cogl_color_equal (&authority0->color, &authority1->color);
}
CoglBool
_cogl_pipeline_lighting_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
CoglPipelineLightingState *state0 = &authority0->big_state->lighting_state;
CoglPipelineLightingState *state1 = &authority1->big_state->lighting_state;
if (memcmp (state0->ambient, state1->ambient, sizeof (float) * 4) != 0)
return FALSE;
if (memcmp (state0->diffuse, state1->diffuse, sizeof (float) * 4) != 0)
return FALSE;
if (memcmp (state0->specular, state1->specular, sizeof (float) * 4) != 0)
return FALSE;
if (memcmp (state0->emission, state1->emission, sizeof (float) * 4) != 0)
return FALSE;
if (state0->shininess != state1->shininess)
return FALSE;
return TRUE;
}
CoglBool
_cogl_pipeline_alpha_func_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
CoglPipelineAlphaFuncState *alpha_state0 =
&authority0->big_state->alpha_state;
CoglPipelineAlphaFuncState *alpha_state1 =
&authority1->big_state->alpha_state;
return alpha_state0->alpha_func == alpha_state1->alpha_func;
}
CoglBool
_cogl_pipeline_alpha_func_reference_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
CoglPipelineAlphaFuncState *alpha_state0 =
&authority0->big_state->alpha_state;
CoglPipelineAlphaFuncState *alpha_state1 =
&authority1->big_state->alpha_state;
return (alpha_state0->alpha_func_reference ==
alpha_state1->alpha_func_reference);
}
CoglBool
_cogl_pipeline_blend_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
CoglPipelineBlendState *blend_state0 = &authority0->big_state->blend_state;
CoglPipelineBlendState *blend_state1 = &authority1->big_state->blend_state;
_COGL_GET_CONTEXT (ctx, FALSE);
if (blend_state0->blend_equation_rgb != blend_state1->blend_equation_rgb)
return FALSE;
if (blend_state0->blend_equation_alpha !=
blend_state1->blend_equation_alpha)
return FALSE;
if (blend_state0->blend_src_factor_alpha !=
blend_state1->blend_src_factor_alpha)
return FALSE;
if (blend_state0->blend_dst_factor_alpha !=
blend_state1->blend_dst_factor_alpha)
return FALSE;
if (blend_state0->blend_src_factor_rgb !=
blend_state1->blend_src_factor_rgb)
return FALSE;
if (blend_state0->blend_dst_factor_rgb !=
blend_state1->blend_dst_factor_rgb)
return FALSE;
if (blend_state0->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
blend_state0->blend_src_factor_rgb == GL_CONSTANT_COLOR ||
blend_state0->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
blend_state0->blend_dst_factor_rgb == GL_CONSTANT_COLOR)
{
if (!cogl_color_equal (&blend_state0->blend_constant,
&blend_state1->blend_constant))
return FALSE;
}
return TRUE;
}
CoglBool
_cogl_pipeline_depth_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
if (authority0->big_state->depth_state.test_enabled == FALSE &&
authority1->big_state->depth_state.test_enabled == FALSE)
return TRUE;
else
{
CoglDepthState *s0 = &authority0->big_state->depth_state;
CoglDepthState *s1 = &authority1->big_state->depth_state;
return s0->test_enabled == s1->test_enabled &&
s0->test_function == s1->test_function &&
s0->write_enabled == s1->write_enabled &&
s0->range_near == s1->range_near &&
s0->range_far == s1->range_far;
}
}
CoglBool
_cogl_pipeline_fog_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
CoglPipelineFogState *fog_state0 = &authority0->big_state->fog_state;
CoglPipelineFogState *fog_state1 = &authority1->big_state->fog_state;
if (fog_state0->enabled == fog_state1->enabled &&
cogl_color_equal (&fog_state0->color, &fog_state1->color) &&
fog_state0->mode == fog_state1->mode &&
fog_state0->density == fog_state1->density &&
fog_state0->z_near == fog_state1->z_near &&
fog_state0->z_far == fog_state1->z_far)
return TRUE;
else
return FALSE;
}
Don't generate GLSL for the point size for default pipelines Previously on GLES2 where there is no builtin point size uniform then we would always add a line to the vertex shader to write to the builtin point size output because when generating the shader it is not possible to determine if the pipeline will be used to draw points or not. This patch changes it so that the default point size is 0.0f which is documented to have undefined results when drawing points. That way we can avoid adding the point size code to the shader in that case. The assumption is that any application that is drawing points will probably have explicitly set the point size on the pipeline anyway so it is not a big deal to change the default size from 1.0f. This adds a new pipeline state flag to track whether the point size is non-zero. This needs to be its own state because altering it needs to cause a different shader to be added to the pipeline cache. The state flags that affect the vertex shader have been changed from a constant to a runtime function because they will be different depending on whether there is a builtin point size uniform. There is also a unit test to ensure that changing the point size does or doesn't generate a new shader depending on the values. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit b2eba06e16b587acbf5c57944a70ceccecb4f175) Conflicts: cogl/cogl-pipeline-private.h cogl/cogl-pipeline-state-private.h cogl/cogl-pipeline-state.c cogl/cogl-pipeline.c
2013-06-20 12:25:49 +00:00
CoglBool
_cogl_pipeline_non_zero_point_size_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return (authority0->big_state->non_zero_point_size ==
authority1->big_state->non_zero_point_size);
}
CoglBool
_cogl_pipeline_point_size_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return authority0->big_state->point_size == authority1->big_state->point_size;
}
Add support for per-vertex point sizes This adds a new function to enable per-vertex point size on a pipeline. This can be set with cogl_pipeline_set_per_vertex_point_size(). Once enabled the point size can be set either by drawing with an attribute named 'cogl_point_size_in' or by writing to the 'cogl_point_size_out' builtin from a snippet. There is a feature flag which must be checked for before using per-vertex point sizes. This will only be set on GL >= 2.0 or on GLES 2.0. GL will only let you set a per-vertex point size from GLSL by writing to gl_PointSize. This is only available in GL2 and not in the older GLSL extensions. The per-vertex point size has its own pipeline state flag so that it can be part of the state that affects vertex shader generation. Having to enable the per vertex point size with a separate function is a bit awkward. Ideally it would work like the color attribute where you can just set it for every vertex in your primitive with cogl_pipeline_set_color or set it per-vertex by just using the attribute. This is harder to get working with the point size because we need to generate a different vertex shader depending on what attributes are bound. I think if we wanted to make this work transparently we would still want to internally have a pipeline property describing whether the shader was generated with per-vertex support so that it would work with the shader cache correctly. Potentially we could make the per-vertex property internal and automatically make a weak pipeline whenever the attribute is bound. However we would then also need to automatically detect when an application is writing to cogl_point_size_out from a snippet. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 8495d9c1c15ce389885a9356d965eabd97758115) Conflicts: cogl/cogl-context.c cogl/cogl-pipeline-private.h cogl/cogl-pipeline.c cogl/cogl-private.h cogl/driver/gl/cogl-pipeline-progend-fixed.c cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
2012-11-08 16:56:02 +00:00
CoglBool
_cogl_pipeline_per_vertex_point_size_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return (authority0->big_state->per_vertex_point_size ==
authority1->big_state->per_vertex_point_size);
}
CoglBool
_cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
CoglPipelineLogicOpsState *logic_ops_state0 = &authority0->big_state->logic_ops_state;
CoglPipelineLogicOpsState *logic_ops_state1 = &authority1->big_state->logic_ops_state;
return logic_ops_state0->color_mask == logic_ops_state1->color_mask;
}
CoglBool
_cogl_pipeline_cull_face_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
CoglPipelineCullFaceState *cull_face_state0
= &authority0->big_state->cull_face_state;
CoglPipelineCullFaceState *cull_face_state1
= &authority1->big_state->cull_face_state;
/* The cull face state is considered equal if two pipelines are both
set to no culling. If the front winding property is ever used for
anything else or the comparison is used not just for drawing then
this would have to change */
if (cull_face_state0->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE)
return cull_face_state1->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE;
return (cull_face_state0->mode == cull_face_state1->mode &&
cull_face_state0->front_winding == cull_face_state1->front_winding);
}
CoglBool
_cogl_pipeline_user_shader_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return (authority0->big_state->user_program ==
authority1->big_state->user_program);
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
typedef struct
{
const CoglBoxedValue **dst_values;
const CoglBoxedValue *src_values;
int override_count;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
} GetUniformsClosure;
static CoglBool
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
get_uniforms_cb (int uniform_num, void *user_data)
{
GetUniformsClosure *data = user_data;
if (data->dst_values[uniform_num] == NULL)
data->dst_values[uniform_num] = data->src_values + data->override_count;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
data->override_count++;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
return TRUE;
}
static void
_cogl_pipeline_get_all_uniform_values (CoglPipeline *pipeline,
const CoglBoxedValue **values)
{
GetUniformsClosure data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
memset (values, 0,
sizeof (const CoglBoxedValue *) * ctx->n_uniform_names);
data.dst_values = values;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
do
{
if ((pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS))
{
const CoglPipelineUniformsState *uniforms_state =
&pipeline->big_state->uniforms_state;
data.override_count = 0;
data.src_values = uniforms_state->override_values;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
_cogl_bitmask_foreach (&uniforms_state->override_mask,
get_uniforms_cb,
&data);
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
pipeline = _cogl_pipeline_get_parent (pipeline);
}
while (pipeline);
}
CoglBool
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
_cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
unsigned long *differences;
const CoglBoxedValue **values0, **values1;
int n_longs;
int i;
_COGL_GET_CONTEXT (ctx, FALSE);
if (authority0 == authority1)
return TRUE;
values0 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names);
values1 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names);
n_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names);
differences = g_alloca (n_longs * sizeof (unsigned long));
memset (differences, 0, sizeof (unsigned long) * n_longs);
_cogl_pipeline_compare_uniform_differences (differences,
authority0,
authority1);
_cogl_pipeline_get_all_uniform_values (authority0, values0);
_cogl_pipeline_get_all_uniform_values (authority1, values1);
COGL_FLAGS_FOREACH_START (differences, n_longs, i)
{
const CoglBoxedValue *value0 = values0[i];
const CoglBoxedValue *value1 = values1[i];
if (value0 == NULL)
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
{
if (value1 != NULL && value1->type != COGL_BOXED_NONE)
return FALSE;
}
else if (value1 == NULL)
{
if (value0 != NULL && value0->type != COGL_BOXED_NONE)
return FALSE;
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
else if (!_cogl_boxed_value_equal (value0, value1))
return FALSE;
}
COGL_FLAGS_FOREACH_END;
return TRUE;
}
CoglBool
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
_cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
vertex_snippets,
&authority1->big_state->
vertex_snippets);
}
CoglBool
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
_cogl_pipeline_fragment_snippets_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
fragment_snippets,
&authority1->big_state->
fragment_snippets);
}
void
cogl_pipeline_get_color (CoglPipeline *pipeline,
CoglColor *color)
{
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
*color = authority->color;
}
/* This is used heavily by the cogl journal when logging quads */
void
_cogl_pipeline_get_colorubv (CoglPipeline *pipeline,
uint8_t *color)
{
CoglPipeline *authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
_cogl_color_get_rgba_4ubv (&authority->color, color);
}
void
cogl_pipeline_set_color (CoglPipeline *pipeline,
const CoglColor *color)
{
CoglPipelineState state = COGL_PIPELINE_STATE_COLOR;
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
if (cogl_color_equal (color, &authority->color))
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, color, FALSE);
pipeline->color = *color;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_color_equal);
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
void
cogl_pipeline_set_color4ub (CoglPipeline *pipeline,
uint8_t red,
uint8_t green,
uint8_t blue,
uint8_t alpha)
{
CoglColor color;
cogl_color_init_from_4ub (&color, red, green, blue, alpha);
cogl_pipeline_set_color (pipeline, &color);
}
void
cogl_pipeline_set_color4f (CoglPipeline *pipeline,
float red,
float green,
float blue,
float alpha)
{
CoglColor color;
cogl_color_init_from_4f (&color, red, green, blue, alpha);
cogl_pipeline_set_color (pipeline, &color);
}
CoglPipelineBlendEnable
_cogl_pipeline_get_blend_enabled (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE);
return authority->blend_enable;
}
static CoglBool
_cogl_pipeline_blend_enable_equal (CoglPipeline *authority0,
CoglPipeline *authority1)
{
return authority0->blend_enable == authority1->blend_enable ? TRUE : FALSE;
}
void
_cogl_pipeline_set_blend_enabled (CoglPipeline *pipeline,
CoglPipelineBlendEnable enable)
{
CoglPipelineState state = COGL_PIPELINE_STATE_BLEND_ENABLE;
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
_COGL_RETURN_IF_FAIL (enable > 1 &&
"don't pass TRUE or FALSE to _set_blend_enabled!");
authority = _cogl_pipeline_get_authority (pipeline, state);
if (authority->blend_enable == enable)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->blend_enable = enable;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_blend_enable_equal);
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
void
cogl_pipeline_get_ambient (CoglPipeline *pipeline,
CoglColor *ambient)
{
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
cogl_color_init_from_4fv (ambient,
authority->big_state->lighting_state.ambient);
}
void
cogl_pipeline_set_ambient (CoglPipeline *pipeline,
const CoglColor *ambient)
{
CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
CoglPipeline *authority;
CoglPipelineLightingState *lighting_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
lighting_state = &authority->big_state->lighting_state;
if (cogl_color_equal (ambient, &lighting_state->ambient))
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
lighting_state = &pipeline->big_state->lighting_state;
lighting_state->ambient[0] = cogl_color_get_red_float (ambient);
lighting_state->ambient[1] = cogl_color_get_green_float (ambient);
lighting_state->ambient[2] = cogl_color_get_blue_float (ambient);
lighting_state->ambient[3] = cogl_color_get_alpha_float (ambient);
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_lighting_state_equal);
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
void
cogl_pipeline_get_diffuse (CoglPipeline *pipeline,
CoglColor *diffuse)
{
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
cogl_color_init_from_4fv (diffuse,
authority->big_state->lighting_state.diffuse);
}
void
cogl_pipeline_set_diffuse (CoglPipeline *pipeline,
const CoglColor *diffuse)
{
CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
CoglPipeline *authority;
CoglPipelineLightingState *lighting_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
lighting_state = &authority->big_state->lighting_state;
if (cogl_color_equal (diffuse, &lighting_state->diffuse))
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
lighting_state = &pipeline->big_state->lighting_state;
lighting_state->diffuse[0] = cogl_color_get_red_float (diffuse);
lighting_state->diffuse[1] = cogl_color_get_green_float (diffuse);
lighting_state->diffuse[2] = cogl_color_get_blue_float (diffuse);
lighting_state->diffuse[3] = cogl_color_get_alpha_float (diffuse);
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_lighting_state_equal);
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
void
cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline,
const CoglColor *color)
{
cogl_pipeline_set_ambient (pipeline, color);
cogl_pipeline_set_diffuse (pipeline, color);
}
void
cogl_pipeline_get_specular (CoglPipeline *pipeline,
CoglColor *specular)
{
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
cogl_color_init_from_4fv (specular,
authority->big_state->lighting_state.specular);
}
void
cogl_pipeline_set_specular (CoglPipeline *pipeline, const CoglColor *specular)
{
CoglPipeline *authority;
CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
CoglPipelineLightingState *lighting_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
lighting_state = &authority->big_state->lighting_state;
if (cogl_color_equal (specular, &lighting_state->specular))
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
lighting_state = &pipeline->big_state->lighting_state;
lighting_state->specular[0] = cogl_color_get_red_float (specular);
lighting_state->specular[1] = cogl_color_get_green_float (specular);
lighting_state->specular[2] = cogl_color_get_blue_float (specular);
lighting_state->specular[3] = cogl_color_get_alpha_float (specular);
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_lighting_state_equal);
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
float
cogl_pipeline_get_shininess (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0);
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
return authority->big_state->lighting_state.shininess;
}
void
cogl_pipeline_set_shininess (CoglPipeline *pipeline,
float shininess)
{
CoglPipeline *authority;
CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
CoglPipelineLightingState *lighting_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
if (shininess < 0.0)
{
g_warning ("Out of range shininess %f supplied for pipeline\n",
shininess);
return;
}
authority = _cogl_pipeline_get_authority (pipeline, state);
lighting_state = &authority->big_state->lighting_state;
if (lighting_state->shininess == shininess)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
lighting_state = &pipeline->big_state->lighting_state;
lighting_state->shininess = shininess;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_lighting_state_equal);
}
void
cogl_pipeline_get_emission (CoglPipeline *pipeline,
CoglColor *emission)
{
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
cogl_color_init_from_4fv (emission,
authority->big_state->lighting_state.emission);
}
void
cogl_pipeline_set_emission (CoglPipeline *pipeline, const CoglColor *emission)
{
CoglPipeline *authority;
CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
CoglPipelineLightingState *lighting_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
lighting_state = &authority->big_state->lighting_state;
if (cogl_color_equal (emission, &lighting_state->emission))
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
lighting_state = &pipeline->big_state->lighting_state;
lighting_state->emission[0] = cogl_color_get_red_float (emission);
lighting_state->emission[1] = cogl_color_get_green_float (emission);
lighting_state->emission[2] = cogl_color_get_blue_float (emission);
lighting_state->emission[3] = cogl_color_get_alpha_float (emission);
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_lighting_state_equal);
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
static void
_cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline,
CoglPipelineAlphaFunc alpha_func)
{
CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC;
CoglPipeline *authority;
CoglPipelineAlphaFuncState *alpha_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
alpha_state = &authority->big_state->alpha_state;
if (alpha_state->alpha_func == alpha_func)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
alpha_state = &pipeline->big_state->alpha_state;
alpha_state->alpha_func = alpha_func;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_alpha_func_state_equal);
}
static void
_cogl_pipeline_set_alpha_test_function_reference (CoglPipeline *pipeline,
float alpha_reference)
{
CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE;
CoglPipeline *authority;
CoglPipelineAlphaFuncState *alpha_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
alpha_state = &authority->big_state->alpha_state;
if (alpha_state->alpha_func_reference == alpha_reference)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
alpha_state = &pipeline->big_state->alpha_state;
alpha_state->alpha_func_reference = alpha_reference;
_cogl_pipeline_update_authority
(pipeline, authority, state,
_cogl_pipeline_alpha_func_reference_state_equal);
}
void
cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline,
CoglPipelineAlphaFunc alpha_func,
float alpha_reference)
{
_cogl_pipeline_set_alpha_test_function (pipeline, alpha_func);
_cogl_pipeline_set_alpha_test_function_reference (pipeline, alpha_reference);
}
CoglPipelineAlphaFunc
cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0);
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_ALPHA_FUNC);
return authority->big_state->alpha_state.alpha_func;
}
float
cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0.0f);
authority =
_cogl_pipeline_get_authority (pipeline,
COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE);
return authority->big_state->alpha_state.alpha_func_reference;
}
Add -Wmissing-declarations to maintainer flags and fix problems This option to GCC makes it give a warning whenever a global function is defined without a declaration. This should catch cases were we've defined a function but forgot to put it in a header. In that case it is either only used within one file so we should make it static or we should declare it in a header. The following changes where made to fix problems: • Some functions were made static • cogl-path.h (the one containing the 1.0 API) was split into two files, one defining the functions and one defining the enums so that cogl-path.c can include the enum and function declarations from the 2.0 API as well as the function declarations from the 1.0 API. • cogl2-clip-state has been removed. This only had one experimental function called cogl_clip_push_from_path but as this is unstable we might as well remove it favour of the equivalent cogl_framebuffer_* API. • The GLX, SDL and WGL winsys's now have a private header to define their get_vtable function instead of directly declaring in the C file where it is called. • All places that were calling COGL_OBJECT_DEFINE need to have the cogl_is_whatever function declared so these have been added either as a public function or in a private header. • Some files that were not including the header containing their function declarations have been fixed to do so. • Any unused error quark functions have been removed. If we later want them we should add them back one by one and add a declaration for them in a header. • _cogl_is_framebuffer has been renamed to cogl_is_framebuffer and made a public function with a declaration in cogl-framebuffer.h • Similarly for CoglOnscreen. • cogl_vdraw_indexed_attributes is called cogl_framebuffer_vdraw_indexed_attributes in the header. The definition has been changed to match the header. • cogl_index_buffer_allocate has been removed. This had no declaration and I'm not sure what it's supposed to do. • CoglJournal has been changed to use the internal CoglObject macro so that it won't define an exported cogl_is_journal symbol. • The _cogl_blah_pointer_from_handle functions have been removed. CoglHandle isn't used much anymore anyway and in the few places where it is used I think it's safe to just use the implicit cast from void* to the right type. • The test-utils.h header for the conformance tests explicitly disables the -Wmissing-declaration option using a pragma because all of the tests declare their main function without a header. Any mistakes relating to missing declarations aren't really important for the tests. • cogl_quaternion_init_from_quaternion and init_from_matrix have been given declarations in cogl-quaternion.h Reviewed-by: Robert Bragg <robert@linux.intel.com>
2012-03-06 18:21:28 +00:00
static GLenum
arg_to_gl_blend_factor (CoglBlendStringArgument *arg)
{
if (arg->source.is_zero)
return GL_ZERO;
if (arg->factor.is_one)
return GL_ONE;
else if (arg->factor.is_src_alpha_saturate)
return GL_SRC_ALPHA_SATURATE;
else if (arg->factor.source.info->type ==
COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR)
{
if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_SRC_COLOR;
else
return GL_SRC_COLOR;
}
else
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_SRC_ALPHA;
else
return GL_SRC_ALPHA;
}
}
else if (arg->factor.source.info->type ==
COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR)
{
if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_DST_COLOR;
else
return GL_DST_COLOR;
}
else
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_DST_ALPHA;
else
return GL_DST_ALPHA;
}
}
#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
else if (arg->factor.source.info->type ==
COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT)
{
if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_CONSTANT_COLOR;
else
return GL_CONSTANT_COLOR;
}
else
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_CONSTANT_ALPHA;
else
return GL_CONSTANT_ALPHA;
}
}
#endif
g_warning ("Unable to determine valid blend factor from blend string\n");
return GL_ONE;
}
Add -Wmissing-declarations to maintainer flags and fix problems This option to GCC makes it give a warning whenever a global function is defined without a declaration. This should catch cases were we've defined a function but forgot to put it in a header. In that case it is either only used within one file so we should make it static or we should declare it in a header. The following changes where made to fix problems: • Some functions were made static • cogl-path.h (the one containing the 1.0 API) was split into two files, one defining the functions and one defining the enums so that cogl-path.c can include the enum and function declarations from the 2.0 API as well as the function declarations from the 1.0 API. • cogl2-clip-state has been removed. This only had one experimental function called cogl_clip_push_from_path but as this is unstable we might as well remove it favour of the equivalent cogl_framebuffer_* API. • The GLX, SDL and WGL winsys's now have a private header to define their get_vtable function instead of directly declaring in the C file where it is called. • All places that were calling COGL_OBJECT_DEFINE need to have the cogl_is_whatever function declared so these have been added either as a public function or in a private header. • Some files that were not including the header containing their function declarations have been fixed to do so. • Any unused error quark functions have been removed. If we later want them we should add them back one by one and add a declaration for them in a header. • _cogl_is_framebuffer has been renamed to cogl_is_framebuffer and made a public function with a declaration in cogl-framebuffer.h • Similarly for CoglOnscreen. • cogl_vdraw_indexed_attributes is called cogl_framebuffer_vdraw_indexed_attributes in the header. The definition has been changed to match the header. • cogl_index_buffer_allocate has been removed. This had no declaration and I'm not sure what it's supposed to do. • CoglJournal has been changed to use the internal CoglObject macro so that it won't define an exported cogl_is_journal symbol. • The _cogl_blah_pointer_from_handle functions have been removed. CoglHandle isn't used much anymore anyway and in the few places where it is used I think it's safe to just use the implicit cast from void* to the right type. • The test-utils.h header for the conformance tests explicitly disables the -Wmissing-declaration option using a pragma because all of the tests declare their main function without a header. Any mistakes relating to missing declarations aren't really important for the tests. • cogl_quaternion_init_from_quaternion and init_from_matrix have been given declarations in cogl-quaternion.h Reviewed-by: Robert Bragg <robert@linux.intel.com>
2012-03-06 18:21:28 +00:00
static void
setup_blend_state (CoglBlendStringStatement *statement,
GLenum *blend_equation,
GLint *blend_src_factor,
GLint *blend_dst_factor)
{
switch (statement->function->type)
{
case COGL_BLEND_STRING_FUNCTION_ADD:
*blend_equation = GL_FUNC_ADD;
break;
/* TODO - add more */
default:
g_warning ("Unsupported blend function given");
*blend_equation = GL_FUNC_ADD;
}
*blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]);
*blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]);
}
CoglBool
cogl_pipeline_set_blend (CoglPipeline *pipeline,
const char *blend_description,
Adds CoglError api Although we use GLib internally in Cogl we would rather not leak GLib api through Cogl's own api, except through explicitly namespaced cogl_glib_ / cogl_gtype_ feature apis. One of the benefits we see to not leaking GLib through Cogl's public API is that documentation for Cogl won't need to first introduce the Glib API to newcomers, thus hopefully lowering the barrier to learning Cogl. This patch provides a Cogl specific typedef for reporting runtime errors which by no coincidence matches the typedef for GError exactly. If Cogl is built with --enable-glib (default) then developers can even safely assume that a CoglError is a GError under the hood. This patch also enforces a consistent policy for when NULL is passed as an error argument and an error is thrown. In this case we log the error and abort the application, instead of silently ignoring it. In common cases where nothing has been implemented to handle a particular error and/or where applications are just printing the error and aborting themselves then this saves some typing. This also seems more consistent with language based exceptions which usually cause a program to abort if they are not explicitly caught (which passing a non-NULL error signifies in this case) Since this policy for NULL error pointers is stricter than the standard GError convention, there is a clear note in the documentation to warn developers that are used to using the GError api. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit b068d5ea09ab32c37e8c965fc8582c85d1b2db46) Note: Since we can't change the Cogl 1.x api the patch was changed to not rename _error_quark() functions to be _error_domain() functions and although it's a bit ugly, instead of providing our own CoglError type that's compatible with GError we simply #define CoglError to GError unless Cogl is built with glib disabled. Note: this patch does technically introduce an API break since it drops the cogl_error_get_type() symbol generated by glib-mkenum (Since the CoglError enum was replaced by a CoglSystemError enum) but for now we are assuming that this will not affect anyone currently using the Cogl API. If this does turn out to be a problem in practice then we would be able to fix this my manually copying an implementation of cogl_error_get_type() generated by glib-mkenum into a compatibility source file and we could also define the original COGL_ERROR_ enums for compatibility too. Note: another minor concern with cherry-picking this patch to the 1.14 branch is that an api scanner would be lead to believe that some APIs have changed, and for example the gobject-introspection parser which understands the semantics of GError will not understand the semantics of CoglError. We expect most people that have tried to use gobject-introspection with Cogl already understand though that it is not well suited to generating bindings of the Cogl api anyway and we aren't aware or anyone depending on such bindings for apis involving GErrors. (GnomeShell only makes very-very minimal use of Cogl via the gjs bindings for the cogl_rectangle and cogl_color apis.) The main reason we have cherry-picked this patch to the 1.14 branch even given the above concerns is that without it it would become very awkward for us to cherry-pick other beneficial patches from master.
2012-08-31 18:28:27 +00:00
CoglError **error)
{
CoglPipelineState state = COGL_PIPELINE_STATE_BLEND;
CoglPipeline *authority;
CoglBlendStringStatement statements[2];
CoglBlendStringStatement *rgb;
CoglBlendStringStatement *a;
int count;
CoglPipelineBlendState *blend_state;
_COGL_GET_CONTEXT (ctx, FALSE);
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
count =
_cogl_blend_string_compile (blend_description,
COGL_BLEND_STRING_CONTEXT_BLENDING,
statements,
Adds CoglError api Although we use GLib internally in Cogl we would rather not leak GLib api through Cogl's own api, except through explicitly namespaced cogl_glib_ / cogl_gtype_ feature apis. One of the benefits we see to not leaking GLib through Cogl's public API is that documentation for Cogl won't need to first introduce the Glib API to newcomers, thus hopefully lowering the barrier to learning Cogl. This patch provides a Cogl specific typedef for reporting runtime errors which by no coincidence matches the typedef for GError exactly. If Cogl is built with --enable-glib (default) then developers can even safely assume that a CoglError is a GError under the hood. This patch also enforces a consistent policy for when NULL is passed as an error argument and an error is thrown. In this case we log the error and abort the application, instead of silently ignoring it. In common cases where nothing has been implemented to handle a particular error and/or where applications are just printing the error and aborting themselves then this saves some typing. This also seems more consistent with language based exceptions which usually cause a program to abort if they are not explicitly caught (which passing a non-NULL error signifies in this case) Since this policy for NULL error pointers is stricter than the standard GError convention, there is a clear note in the documentation to warn developers that are used to using the GError api. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit b068d5ea09ab32c37e8c965fc8582c85d1b2db46) Note: Since we can't change the Cogl 1.x api the patch was changed to not rename _error_quark() functions to be _error_domain() functions and although it's a bit ugly, instead of providing our own CoglError type that's compatible with GError we simply #define CoglError to GError unless Cogl is built with glib disabled. Note: this patch does technically introduce an API break since it drops the cogl_error_get_type() symbol generated by glib-mkenum (Since the CoglError enum was replaced by a CoglSystemError enum) but for now we are assuming that this will not affect anyone currently using the Cogl API. If this does turn out to be a problem in practice then we would be able to fix this my manually copying an implementation of cogl_error_get_type() generated by glib-mkenum into a compatibility source file and we could also define the original COGL_ERROR_ enums for compatibility too. Note: another minor concern with cherry-picking this patch to the 1.14 branch is that an api scanner would be lead to believe that some APIs have changed, and for example the gobject-introspection parser which understands the semantics of GError will not understand the semantics of CoglError. We expect most people that have tried to use gobject-introspection with Cogl already understand though that it is not well suited to generating bindings of the Cogl api anyway and we aren't aware or anyone depending on such bindings for apis involving GErrors. (GnomeShell only makes very-very minimal use of Cogl via the gjs bindings for the cogl_rectangle and cogl_color apis.) The main reason we have cherry-picked this patch to the 1.14 branch even given the above concerns is that without it it would become very awkward for us to cherry-pick other beneficial patches from master.
2012-08-31 18:28:27 +00:00
error);
if (!count)
Adds CoglError api Although we use GLib internally in Cogl we would rather not leak GLib api through Cogl's own api, except through explicitly namespaced cogl_glib_ / cogl_gtype_ feature apis. One of the benefits we see to not leaking GLib through Cogl's public API is that documentation for Cogl won't need to first introduce the Glib API to newcomers, thus hopefully lowering the barrier to learning Cogl. This patch provides a Cogl specific typedef for reporting runtime errors which by no coincidence matches the typedef for GError exactly. If Cogl is built with --enable-glib (default) then developers can even safely assume that a CoglError is a GError under the hood. This patch also enforces a consistent policy for when NULL is passed as an error argument and an error is thrown. In this case we log the error and abort the application, instead of silently ignoring it. In common cases where nothing has been implemented to handle a particular error and/or where applications are just printing the error and aborting themselves then this saves some typing. This also seems more consistent with language based exceptions which usually cause a program to abort if they are not explicitly caught (which passing a non-NULL error signifies in this case) Since this policy for NULL error pointers is stricter than the standard GError convention, there is a clear note in the documentation to warn developers that are used to using the GError api. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit b068d5ea09ab32c37e8c965fc8582c85d1b2db46) Note: Since we can't change the Cogl 1.x api the patch was changed to not rename _error_quark() functions to be _error_domain() functions and although it's a bit ugly, instead of providing our own CoglError type that's compatible with GError we simply #define CoglError to GError unless Cogl is built with glib disabled. Note: this patch does technically introduce an API break since it drops the cogl_error_get_type() symbol generated by glib-mkenum (Since the CoglError enum was replaced by a CoglSystemError enum) but for now we are assuming that this will not affect anyone currently using the Cogl API. If this does turn out to be a problem in practice then we would be able to fix this my manually copying an implementation of cogl_error_get_type() generated by glib-mkenum into a compatibility source file and we could also define the original COGL_ERROR_ enums for compatibility too. Note: another minor concern with cherry-picking this patch to the 1.14 branch is that an api scanner would be lead to believe that some APIs have changed, and for example the gobject-introspection parser which understands the semantics of GError will not understand the semantics of CoglError. We expect most people that have tried to use gobject-introspection with Cogl already understand though that it is not well suited to generating bindings of the Cogl api anyway and we aren't aware or anyone depending on such bindings for apis involving GErrors. (GnomeShell only makes very-very minimal use of Cogl via the gjs bindings for the cogl_rectangle and cogl_color apis.) The main reason we have cherry-picked this patch to the 1.14 branch even given the above concerns is that without it it would become very awkward for us to cherry-pick other beneficial patches from master.
2012-08-31 18:28:27 +00:00
return FALSE;
if (count == 1)
rgb = a = statements;
else
{
rgb = &statements[0];
a = &statements[1];
}
authority =
_cogl_pipeline_get_authority (pipeline, state);
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
blend_state = &pipeline->big_state->blend_state;
setup_blend_state (rgb,
&blend_state->blend_equation_rgb,
&blend_state->blend_src_factor_rgb,
&blend_state->blend_dst_factor_rgb);
setup_blend_state (a,
&blend_state->blend_equation_alpha,
&blend_state->blend_src_factor_alpha,
&blend_state->blend_dst_factor_alpha);
/* If we are the current authority see if we can revert to one of our
* ancestors being the authority */
if (pipeline == authority &&
_cogl_pipeline_get_parent (authority) != NULL)
{
CoglPipeline *parent = _cogl_pipeline_get_parent (authority);
CoglPipeline *old_authority =
_cogl_pipeline_get_authority (parent, state);
if (_cogl_pipeline_blend_state_equal (authority, old_authority))
pipeline->differences &= ~state;
}
/* 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 (pipeline != authority)
{
pipeline->differences |= state;
_cogl_pipeline_prune_redundant_ancestry (pipeline);
}
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
return TRUE;
}
void
cogl_pipeline_set_blend_constant (CoglPipeline *pipeline,
const CoglColor *constant_color)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLEND_CONSTANT))
return;
#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
{
CoglPipelineState state = COGL_PIPELINE_STATE_BLEND;
CoglPipeline *authority;
CoglPipelineBlendState *blend_state;
authority = _cogl_pipeline_get_authority (pipeline, state);
blend_state = &authority->big_state->blend_state;
if (cogl_color_equal (constant_color, &blend_state->blend_constant))
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
blend_state = &pipeline->big_state->blend_state;
blend_state->blend_constant = *constant_color;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_blend_state_equal);
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
#endif
}
CoglHandle
cogl_pipeline_get_user_program (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), COGL_INVALID_HANDLE);
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER);
return authority->big_state->user_program;
}
/* XXX: for now we don't mind if the program has vertex shaders
* attached but if we ever make a similar API public we should only
* allow attaching of programs containing fragment shaders. Eventually
* we will have a CoglPipeline abstraction to also cover vertex
* processing.
*/
void
cogl_pipeline_set_user_program (CoglPipeline *pipeline,
CoglHandle program)
{
CoglPipelineState state = COGL_PIPELINE_STATE_USER_SHADER;
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
if (authority->big_state->user_program == program)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
if (program != COGL_INVALID_HANDLE)
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)
2012-09-25 20:08:10 +00:00
_cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_UNDEFINED);
/* If we are the current authority see if we can revert to one of our
* ancestors being the authority */
if (pipeline == authority &&
_cogl_pipeline_get_parent (authority) != NULL)
{
CoglPipeline *parent = _cogl_pipeline_get_parent (authority);
CoglPipeline *old_authority =
_cogl_pipeline_get_authority (parent, state);
if (old_authority->big_state->user_program == program)
pipeline->differences &= ~state;
}
else if (pipeline != authority)
{
/* 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... */
pipeline->differences |= state;
_cogl_pipeline_prune_redundant_ancestry (pipeline);
}
if (program != COGL_INVALID_HANDLE)
cogl_handle_ref (program);
if (authority == pipeline &&
pipeline->big_state->user_program != COGL_INVALID_HANDLE)
cogl_handle_unref (pipeline->big_state->user_program);
pipeline->big_state->user_program = program;
pipeline: improve real_blend_enable checks Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
2013-05-16 14:19:30 +00:00
pipeline->dirty_real_blend_enable = TRUE;
}
CoglBool
cogl_pipeline_set_depth_state (CoglPipeline *pipeline,
const CoglDepthState *depth_state,
Adds CoglError api Although we use GLib internally in Cogl we would rather not leak GLib api through Cogl's own api, except through explicitly namespaced cogl_glib_ / cogl_gtype_ feature apis. One of the benefits we see to not leaking GLib through Cogl's public API is that documentation for Cogl won't need to first introduce the Glib API to newcomers, thus hopefully lowering the barrier to learning Cogl. This patch provides a Cogl specific typedef for reporting runtime errors which by no coincidence matches the typedef for GError exactly. If Cogl is built with --enable-glib (default) then developers can even safely assume that a CoglError is a GError under the hood. This patch also enforces a consistent policy for when NULL is passed as an error argument and an error is thrown. In this case we log the error and abort the application, instead of silently ignoring it. In common cases where nothing has been implemented to handle a particular error and/or where applications are just printing the error and aborting themselves then this saves some typing. This also seems more consistent with language based exceptions which usually cause a program to abort if they are not explicitly caught (which passing a non-NULL error signifies in this case) Since this policy for NULL error pointers is stricter than the standard GError convention, there is a clear note in the documentation to warn developers that are used to using the GError api. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit b068d5ea09ab32c37e8c965fc8582c85d1b2db46) Note: Since we can't change the Cogl 1.x api the patch was changed to not rename _error_quark() functions to be _error_domain() functions and although it's a bit ugly, instead of providing our own CoglError type that's compatible with GError we simply #define CoglError to GError unless Cogl is built with glib disabled. Note: this patch does technically introduce an API break since it drops the cogl_error_get_type() symbol generated by glib-mkenum (Since the CoglError enum was replaced by a CoglSystemError enum) but for now we are assuming that this will not affect anyone currently using the Cogl API. If this does turn out to be a problem in practice then we would be able to fix this my manually copying an implementation of cogl_error_get_type() generated by glib-mkenum into a compatibility source file and we could also define the original COGL_ERROR_ enums for compatibility too. Note: another minor concern with cherry-picking this patch to the 1.14 branch is that an api scanner would be lead to believe that some APIs have changed, and for example the gobject-introspection parser which understands the semantics of GError will not understand the semantics of CoglError. We expect most people that have tried to use gobject-introspection with Cogl already understand though that it is not well suited to generating bindings of the Cogl api anyway and we aren't aware or anyone depending on such bindings for apis involving GErrors. (GnomeShell only makes very-very minimal use of Cogl via the gjs bindings for the cogl_rectangle and cogl_color apis.) The main reason we have cherry-picked this patch to the 1.14 branch even given the above concerns is that without it it would become very awkward for us to cherry-pick other beneficial patches from master.
2012-08-31 18:28:27 +00:00
CoglError **error)
{
CoglPipelineState state = COGL_PIPELINE_STATE_DEPTH;
CoglPipeline *authority;
CoglDepthState *orig_state;
_COGL_GET_CONTEXT (ctx, FALSE);
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
_COGL_RETURN_VAL_IF_FAIL (depth_state->magic == COGL_DEPTH_STATE_MAGIC, FALSE);
authority = _cogl_pipeline_get_authority (pipeline, state);
orig_state = &authority->big_state->depth_state;
if (orig_state->test_enabled == depth_state->test_enabled &&
orig_state->write_enabled == depth_state->write_enabled &&
orig_state->test_function == depth_state->test_function &&
orig_state->range_near == depth_state->range_near &&
orig_state->range_far == depth_state->range_far)
return TRUE;
if (ctx->driver == COGL_DRIVER_GLES1 &&
(depth_state->range_near != 0 ||
depth_state->range_far != 1))
{
Adds CoglError api Although we use GLib internally in Cogl we would rather not leak GLib api through Cogl's own api, except through explicitly namespaced cogl_glib_ / cogl_gtype_ feature apis. One of the benefits we see to not leaking GLib through Cogl's public API is that documentation for Cogl won't need to first introduce the Glib API to newcomers, thus hopefully lowering the barrier to learning Cogl. This patch provides a Cogl specific typedef for reporting runtime errors which by no coincidence matches the typedef for GError exactly. If Cogl is built with --enable-glib (default) then developers can even safely assume that a CoglError is a GError under the hood. This patch also enforces a consistent policy for when NULL is passed as an error argument and an error is thrown. In this case we log the error and abort the application, instead of silently ignoring it. In common cases where nothing has been implemented to handle a particular error and/or where applications are just printing the error and aborting themselves then this saves some typing. This also seems more consistent with language based exceptions which usually cause a program to abort if they are not explicitly caught (which passing a non-NULL error signifies in this case) Since this policy for NULL error pointers is stricter than the standard GError convention, there is a clear note in the documentation to warn developers that are used to using the GError api. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit b068d5ea09ab32c37e8c965fc8582c85d1b2db46) Note: Since we can't change the Cogl 1.x api the patch was changed to not rename _error_quark() functions to be _error_domain() functions and although it's a bit ugly, instead of providing our own CoglError type that's compatible with GError we simply #define CoglError to GError unless Cogl is built with glib disabled. Note: this patch does technically introduce an API break since it drops the cogl_error_get_type() symbol generated by glib-mkenum (Since the CoglError enum was replaced by a CoglSystemError enum) but for now we are assuming that this will not affect anyone currently using the Cogl API. If this does turn out to be a problem in practice then we would be able to fix this my manually copying an implementation of cogl_error_get_type() generated by glib-mkenum into a compatibility source file and we could also define the original COGL_ERROR_ enums for compatibility too. Note: another minor concern with cherry-picking this patch to the 1.14 branch is that an api scanner would be lead to believe that some APIs have changed, and for example the gobject-introspection parser which understands the semantics of GError will not understand the semantics of CoglError. We expect most people that have tried to use gobject-introspection with Cogl already understand though that it is not well suited to generating bindings of the Cogl api anyway and we aren't aware or anyone depending on such bindings for apis involving GErrors. (GnomeShell only makes very-very minimal use of Cogl via the gjs bindings for the cogl_rectangle and cogl_color apis.) The main reason we have cherry-picked this patch to the 1.14 branch even given the above concerns is that without it it would become very awkward for us to cherry-pick other beneficial patches from master.
2012-08-31 18:28:27 +00:00
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"glDepthRange not available on GLES 1");
return FALSE;
}
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->big_state->depth_state = *depth_state;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_depth_state_equal);
return TRUE;
}
void
cogl_pipeline_get_depth_state (CoglPipeline *pipeline,
CoglDepthState *state)
{
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH);
*state = authority->big_state->depth_state;
}
CoglColorMask
cogl_pipeline_get_color_mask (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0);
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS);
return authority->big_state->logic_ops_state.color_mask;
}
void
cogl_pipeline_set_color_mask (CoglPipeline *pipeline,
CoglColorMask color_mask)
{
CoglPipelineState state = COGL_PIPELINE_STATE_LOGIC_OPS;
CoglPipeline *authority;
CoglPipelineLogicOpsState *logic_ops_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
logic_ops_state = &authority->big_state->logic_ops_state;
if (logic_ops_state->color_mask == color_mask)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
logic_ops_state = &pipeline->big_state->logic_ops_state;
logic_ops_state->color_mask = color_mask;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_logic_ops_state_equal);
}
void
_cogl_pipeline_set_fog_state (CoglPipeline *pipeline,
const CoglPipelineFogState *fog_state)
{
CoglPipelineState state = COGL_PIPELINE_STATE_FOG;
CoglPipeline *authority;
CoglPipelineFogState *current_fog_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
current_fog_state = &authority->big_state->fog_state;
if (current_fog_state->enabled == fog_state->enabled &&
cogl_color_equal (&current_fog_state->color, &fog_state->color) &&
current_fog_state->mode == fog_state->mode &&
current_fog_state->density == fog_state->density &&
current_fog_state->z_near == fog_state->z_near &&
current_fog_state->z_far == fog_state->z_far)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->big_state->fog_state = *fog_state;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_fog_state_equal);
}
void
cogl_pipeline_set_cull_face_mode (CoglPipeline *pipeline,
CoglPipelineCullFaceMode cull_face_mode)
{
CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
CoglPipeline *authority;
CoglPipelineCullFaceState *cull_face_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
cull_face_state = &authority->big_state->cull_face_state;
if (cull_face_state->mode == cull_face_mode)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->big_state->cull_face_state.mode = cull_face_mode;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_cull_face_state_equal);
}
void
cogl_pipeline_set_front_face_winding (CoglPipeline *pipeline,
CoglWinding front_winding)
{
CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
CoglPipeline *authority;
CoglPipelineCullFaceState *cull_face_state;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
cull_face_state = &authority->big_state->cull_face_state;
if (cull_face_state->front_winding == front_winding)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->big_state->cull_face_state.front_winding = front_winding;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_cull_face_state_equal);
}
CoglPipelineCullFaceMode
cogl_pipeline_get_cull_face_mode (CoglPipeline *pipeline)
{
CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline),
COGL_PIPELINE_CULL_FACE_MODE_NONE);
authority = _cogl_pipeline_get_authority (pipeline, state);
return authority->big_state->cull_face_state.mode;
}
CoglWinding
cogl_pipeline_get_front_face_winding (CoglPipeline *pipeline)
{
CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline),
COGL_PIPELINE_CULL_FACE_MODE_NONE);
authority = _cogl_pipeline_get_authority (pipeline, state);
return authority->big_state->cull_face_state.front_winding;
}
float
cogl_pipeline_get_point_size (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
authority =
_cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE);
return authority->big_state->point_size;
}
Don't generate GLSL for the point size for default pipelines Previously on GLES2 where there is no builtin point size uniform then we would always add a line to the vertex shader to write to the builtin point size output because when generating the shader it is not possible to determine if the pipeline will be used to draw points or not. This patch changes it so that the default point size is 0.0f which is documented to have undefined results when drawing points. That way we can avoid adding the point size code to the shader in that case. The assumption is that any application that is drawing points will probably have explicitly set the point size on the pipeline anyway so it is not a big deal to change the default size from 1.0f. This adds a new pipeline state flag to track whether the point size is non-zero. This needs to be its own state because altering it needs to cause a different shader to be added to the pipeline cache. The state flags that affect the vertex shader have been changed from a constant to a runtime function because they will be different depending on whether there is a builtin point size uniform. There is also a unit test to ensure that changing the point size does or doesn't generate a new shader depending on the values. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit b2eba06e16b587acbf5c57944a70ceccecb4f175) Conflicts: cogl/cogl-pipeline-private.h cogl/cogl-pipeline-state-private.h cogl/cogl-pipeline-state.c cogl/cogl-pipeline.c
2013-06-20 12:25:49 +00:00
static void
_cogl_pipeline_set_non_zero_point_size (CoglPipeline *pipeline,
CoglBool value)
{
CoglPipelineState state = COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE;
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->big_state->non_zero_point_size = !!value;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_non_zero_point_size_equal);
}
void
cogl_pipeline_set_point_size (CoglPipeline *pipeline,
float point_size)
{
CoglPipelineState state = COGL_PIPELINE_STATE_POINT_SIZE;
CoglPipeline *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
authority = _cogl_pipeline_get_authority (pipeline, state);
if (authority->big_state->point_size == point_size)
return;
Don't generate GLSL for the point size for default pipelines Previously on GLES2 where there is no builtin point size uniform then we would always add a line to the vertex shader to write to the builtin point size output because when generating the shader it is not possible to determine if the pipeline will be used to draw points or not. This patch changes it so that the default point size is 0.0f which is documented to have undefined results when drawing points. That way we can avoid adding the point size code to the shader in that case. The assumption is that any application that is drawing points will probably have explicitly set the point size on the pipeline anyway so it is not a big deal to change the default size from 1.0f. This adds a new pipeline state flag to track whether the point size is non-zero. This needs to be its own state because altering it needs to cause a different shader to be added to the pipeline cache. The state flags that affect the vertex shader have been changed from a constant to a runtime function because they will be different depending on whether there is a builtin point size uniform. There is also a unit test to ensure that changing the point size does or doesn't generate a new shader depending on the values. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit b2eba06e16b587acbf5c57944a70ceccecb4f175) Conflicts: cogl/cogl-pipeline-private.h cogl/cogl-pipeline-state-private.h cogl/cogl-pipeline-state.c cogl/cogl-pipeline.c
2013-06-20 12:25:49 +00:00
/* Changing the point size may additionally modify
* COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE. */
if ((authority->big_state->point_size > 0.0f) != (point_size > 0.0f))
_cogl_pipeline_set_non_zero_point_size (pipeline, point_size > 0.0f);
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->big_state->point_size = point_size;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_point_size_equal);
}
Add support for per-vertex point sizes This adds a new function to enable per-vertex point size on a pipeline. This can be set with cogl_pipeline_set_per_vertex_point_size(). Once enabled the point size can be set either by drawing with an attribute named 'cogl_point_size_in' or by writing to the 'cogl_point_size_out' builtin from a snippet. There is a feature flag which must be checked for before using per-vertex point sizes. This will only be set on GL >= 2.0 or on GLES 2.0. GL will only let you set a per-vertex point size from GLSL by writing to gl_PointSize. This is only available in GL2 and not in the older GLSL extensions. The per-vertex point size has its own pipeline state flag so that it can be part of the state that affects vertex shader generation. Having to enable the per vertex point size with a separate function is a bit awkward. Ideally it would work like the color attribute where you can just set it for every vertex in your primitive with cogl_pipeline_set_color or set it per-vertex by just using the attribute. This is harder to get working with the point size because we need to generate a different vertex shader depending on what attributes are bound. I think if we wanted to make this work transparently we would still want to internally have a pipeline property describing whether the shader was generated with per-vertex support so that it would work with the shader cache correctly. Potentially we could make the per-vertex property internal and automatically make a weak pipeline whenever the attribute is bound. However we would then also need to automatically detect when an application is writing to cogl_point_size_out from a snippet. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 8495d9c1c15ce389885a9356d965eabd97758115) Conflicts: cogl/cogl-context.c cogl/cogl-pipeline-private.h cogl/cogl-pipeline.c cogl/cogl-private.h cogl/driver/gl/cogl-pipeline-progend-fixed.c cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
2012-11-08 16:56:02 +00:00
CoglBool
cogl_pipeline_set_per_vertex_point_size (CoglPipeline *pipeline,
CoglBool enable,
CoglError **error)
{
CoglPipelineState state = COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE;
CoglPipeline *authority;
_COGL_GET_CONTEXT (ctx, FALSE);
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
authority = _cogl_pipeline_get_authority (pipeline, state);
enable = !!enable;
if (authority->big_state->per_vertex_point_size == enable)
return TRUE;
if (enable && !cogl_has_feature (ctx, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Per-vertex point size is not supported");
return FALSE;
}
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
pipeline->big_state->per_vertex_point_size = enable;
_cogl_pipeline_update_authority (pipeline, authority, state,
_cogl_pipeline_point_size_equal);
return TRUE;
}
CoglBool
cogl_pipeline_get_per_vertex_point_size (CoglPipeline *pipeline)
{
CoglPipeline *authority;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
authority =
_cogl_pipeline_get_authority (pipeline,
COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE);
return authority->big_state->per_vertex_point_size;
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
static CoglBoxedValue *
_cogl_pipeline_override_uniform (CoglPipeline *pipeline,
int location)
{
CoglPipelineState state = COGL_PIPELINE_STATE_UNIFORMS;
CoglPipelineUniformsState *uniforms_state;
int override_index;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
_COGL_GET_CONTEXT (ctx, NULL);
g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL);
g_return_val_if_fail (location >= 0, NULL);
g_return_val_if_fail (location < ctx->n_uniform_names, NULL);
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
uniforms_state = &pipeline->big_state->uniforms_state;
/* Count the number of bits that are set below this location. That
should give us the position where our new value should lie */
override_index = _cogl_bitmask_popcount_upto (&uniforms_state->override_mask,
location);
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
_cogl_bitmask_set (&uniforms_state->changed_mask, location, TRUE);
/* If this pipeline already has an override for this value then we
can just use it directly */
if (_cogl_bitmask_get (&uniforms_state->override_mask, location))
return uniforms_state->override_values + override_index;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
/* We need to create a new override value in the right position
within the array. This is pretty inefficient but the hope is that
it will be much more common to modify an existing uniform rather
than modify a new one so it is more important to optimise the
former case. */
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
if (uniforms_state->override_values == NULL)
{
g_assert (override_index == 0);
uniforms_state->override_values = g_new (CoglBoxedValue, 1);
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
else
{
/* We need to grow the array and copy in the old values */
CoglBoxedValue *old_values = uniforms_state->override_values;
int old_size = _cogl_bitmask_popcount (&uniforms_state->override_mask);
uniforms_state->override_values = g_new (CoglBoxedValue, old_size + 1);
/* Copy in the old values leaving a gap for the new value */
memcpy (uniforms_state->override_values,
old_values,
sizeof (CoglBoxedValue) * override_index);
memcpy (uniforms_state->override_values + override_index + 1,
old_values + override_index,
sizeof (CoglBoxedValue) * (old_size - override_index));
g_free (old_values);
}
_cogl_boxed_value_init (uniforms_state->override_values + override_index);
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
_cogl_bitmask_set (&uniforms_state->override_mask, location, TRUE);
return uniforms_state->override_values + override_index;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
}
void
cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline,
int uniform_location,
float value)
{
CoglBoxedValue *boxed_value;
boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
_cogl_boxed_value_set_1f (boxed_value, value);
}
void
cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline,
int uniform_location,
int value)
{
CoglBoxedValue *boxed_value;
boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
_cogl_boxed_value_set_1i (boxed_value, value);
}
void
cogl_pipeline_set_uniform_float (CoglPipeline *pipeline,
int uniform_location,
int n_components,
int count,
const float *value)
{
CoglBoxedValue *boxed_value;
boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
_cogl_boxed_value_set_float (boxed_value, n_components, count, value);
}
void
cogl_pipeline_set_uniform_int (CoglPipeline *pipeline,
int uniform_location,
int n_components,
int count,
const int *value)
{
CoglBoxedValue *boxed_value;
boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
_cogl_boxed_value_set_int (boxed_value, n_components, count, value);
}
void
cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline,
int uniform_location,
int dimensions,
int count,
CoglBool transpose,
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
const float *value)
{
CoglBoxedValue *boxed_value;
boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
_cogl_boxed_value_set_matrix (boxed_value,
dimensions,
count,
transpose,
value);
}
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
static void
_cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline,
CoglSnippet *snippet)
{
CoglPipelineState state = COGL_PIPELINE_STATE_VERTEX_SNIPPETS;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
_cogl_pipeline_snippet_list_add (&pipeline->big_state->vertex_snippets,
snippet);
}
static void
_cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline,
CoglSnippet *snippet)
{
CoglPipelineState state = COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS;
/* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
_cogl_pipeline_snippet_list_add (&pipeline->big_state->fragment_snippets,
snippet);
}
void
cogl_pipeline_add_snippet (CoglPipeline *pipeline,
CoglSnippet *snippet)
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
{
g_return_if_fail (cogl_is_pipeline (pipeline));
g_return_if_fail (cogl_is_snippet (snippet));
g_return_if_fail (snippet->hook < COGL_SNIPPET_FIRST_LAYER_HOOK);
if (snippet->hook < COGL_SNIPPET_FIRST_PIPELINE_FRAGMENT_HOOK)
_cogl_pipeline_add_vertex_snippet (pipeline, snippet);
else
_cogl_pipeline_add_fragment_snippet (pipeline, snippet);
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
}
CoglBool
_cogl_pipeline_has_non_layer_vertex_snippets (CoglPipeline *pipeline)
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
{
CoglPipeline *authority =
_cogl_pipeline_get_authority (pipeline,
COGL_PIPELINE_STATE_VERTEX_SNIPPETS);
return authority->big_state->vertex_snippets.entries != NULL;
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
}
static CoglBool
check_layer_has_vertex_snippet (CoglPipelineLayer *layer,
void *user_data)
{
unsigned long state = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS;
CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, state);
CoglBool *found_vertex_snippet = user_data;
if (authority->big_state->vertex_snippets.entries)
{
*found_vertex_snippet = TRUE;
return FALSE;
}
return TRUE;
}
CoglBool
_cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline)
{
CoglBool found_vertex_snippet = FALSE;
if (_cogl_pipeline_has_non_layer_vertex_snippets (pipeline))
return TRUE;
_cogl_pipeline_foreach_layer_internal (pipeline,
check_layer_has_vertex_snippet,
&found_vertex_snippet);
return found_vertex_snippet;
}
CoglBool
_cogl_pipeline_has_non_layer_fragment_snippets (CoglPipeline *pipeline)
{
CoglPipeline *authority =
_cogl_pipeline_get_authority (pipeline,
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS);
return authority->big_state->fragment_snippets.entries != NULL;
}
static CoglBool
check_layer_has_fragment_snippet (CoglPipelineLayer *layer,
void *user_data)
{
unsigned long state = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS;
CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, state);
CoglBool *found_fragment_snippet = user_data;
if (authority->big_state->fragment_snippets.entries)
{
*found_fragment_snippet = TRUE;
return FALSE;
}
return TRUE;
}
CoglBool
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
_cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline)
{
CoglBool found_fragment_snippet = FALSE;
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
if (_cogl_pipeline_has_non_layer_fragment_snippets (pipeline))
return TRUE;
_cogl_pipeline_foreach_layer_internal (pipeline,
check_layer_has_fragment_snippet,
&found_fragment_snippet);
return found_fragment_snippet;
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
}
void
_cogl_pipeline_hash_color_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->color,
_COGL_COLOR_DATA_SIZE);
}
void
_cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
uint8_t blend_enable = authority->blend_enable;
state->hash = _cogl_util_one_at_a_time_hash (state->hash, &blend_enable, 1);
}
void
_cogl_pipeline_hash_lighting_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglPipelineLightingState *lighting_state =
&authority->big_state->lighting_state;
state->hash =
_cogl_util_one_at_a_time_hash (state->hash, lighting_state,
sizeof (CoglPipelineLightingState));
}
void
_cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state;
state->hash =
_cogl_util_one_at_a_time_hash (state->hash, &alpha_state->alpha_func,
sizeof (alpha_state->alpha_func));
}
void
_cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state;
float ref = alpha_state->alpha_func_reference;
state->hash =
_cogl_util_one_at_a_time_hash (state->hash, &ref, sizeof (float));
}
void
_cogl_pipeline_hash_blend_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglPipelineBlendState *blend_state = &authority->big_state->blend_state;
unsigned int hash;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!authority->real_blend_enable)
return;
hash = state->hash;
hash =
_cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_rgb,
sizeof (blend_state->blend_equation_rgb));
hash =
_cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_alpha,
sizeof (blend_state->blend_equation_alpha));
hash =
_cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_alpha,
sizeof (blend_state->blend_src_factor_alpha));
hash =
_cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_alpha,
sizeof (blend_state->blend_dst_factor_alpha));
if (blend_state->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
blend_state->blend_src_factor_rgb == GL_CONSTANT_COLOR ||
blend_state->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
blend_state->blend_dst_factor_rgb == GL_CONSTANT_COLOR)
{
hash =
_cogl_util_one_at_a_time_hash (hash, &blend_state->blend_constant,
sizeof (blend_state->blend_constant));
}
hash =
_cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_rgb,
sizeof (blend_state->blend_src_factor_rgb));
hash =
_cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_rgb,
sizeof (blend_state->blend_dst_factor_rgb));
state->hash = hash;
}
void
_cogl_pipeline_hash_user_shader_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglHandle user_program = authority->big_state->user_program;
state->hash = _cogl_util_one_at_a_time_hash (state->hash, &user_program,
sizeof (user_program));
}
void
_cogl_pipeline_hash_depth_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglDepthState *depth_state = &authority->big_state->depth_state;
unsigned int hash = state->hash;
if (depth_state->test_enabled)
{
uint8_t enabled = depth_state->test_enabled;
CoglDepthTestFunction function = depth_state->test_function;
hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled));
hash = _cogl_util_one_at_a_time_hash (hash, &function, sizeof (function));
}
if (depth_state->write_enabled)
{
uint8_t enabled = depth_state->write_enabled;
float near_val = depth_state->range_near;
float far_val = depth_state->range_far;
hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled));
hash = _cogl_util_one_at_a_time_hash (hash, &near_val, sizeof (near_val));
hash = _cogl_util_one_at_a_time_hash (hash, &far_val, sizeof (far_val));
}
state->hash = hash;
}
void
_cogl_pipeline_hash_fog_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglPipelineFogState *fog_state = &authority->big_state->fog_state;
unsigned long hash = state->hash;
if (!fog_state->enabled)
hash = _cogl_util_one_at_a_time_hash (hash, &fog_state->enabled,
sizeof (fog_state->enabled));
else
hash = _cogl_util_one_at_a_time_hash (hash, &fog_state,
sizeof (CoglPipelineFogState));
state->hash = hash;
}
Don't generate GLSL for the point size for default pipelines Previously on GLES2 where there is no builtin point size uniform then we would always add a line to the vertex shader to write to the builtin point size output because when generating the shader it is not possible to determine if the pipeline will be used to draw points or not. This patch changes it so that the default point size is 0.0f which is documented to have undefined results when drawing points. That way we can avoid adding the point size code to the shader in that case. The assumption is that any application that is drawing points will probably have explicitly set the point size on the pipeline anyway so it is not a big deal to change the default size from 1.0f. This adds a new pipeline state flag to track whether the point size is non-zero. This needs to be its own state because altering it needs to cause a different shader to be added to the pipeline cache. The state flags that affect the vertex shader have been changed from a constant to a runtime function because they will be different depending on whether there is a builtin point size uniform. There is also a unit test to ensure that changing the point size does or doesn't generate a new shader depending on the values. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit b2eba06e16b587acbf5c57944a70ceccecb4f175) Conflicts: cogl/cogl-pipeline-private.h cogl/cogl-pipeline-state-private.h cogl/cogl-pipeline-state.c cogl/cogl-pipeline.c
2013-06-20 12:25:49 +00:00
void
_cogl_pipeline_hash_non_zero_point_size_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglBool non_zero_point_size = authority->big_state->non_zero_point_size;
state->hash = _cogl_util_one_at_a_time_hash (state->hash,
&non_zero_point_size,
sizeof (non_zero_point_size));
}
void
_cogl_pipeline_hash_point_size_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
float point_size = authority->big_state->point_size;
state->hash = _cogl_util_one_at_a_time_hash (state->hash, &point_size,
sizeof (point_size));
}
Add support for per-vertex point sizes This adds a new function to enable per-vertex point size on a pipeline. This can be set with cogl_pipeline_set_per_vertex_point_size(). Once enabled the point size can be set either by drawing with an attribute named 'cogl_point_size_in' or by writing to the 'cogl_point_size_out' builtin from a snippet. There is a feature flag which must be checked for before using per-vertex point sizes. This will only be set on GL >= 2.0 or on GLES 2.0. GL will only let you set a per-vertex point size from GLSL by writing to gl_PointSize. This is only available in GL2 and not in the older GLSL extensions. The per-vertex point size has its own pipeline state flag so that it can be part of the state that affects vertex shader generation. Having to enable the per vertex point size with a separate function is a bit awkward. Ideally it would work like the color attribute where you can just set it for every vertex in your primitive with cogl_pipeline_set_color or set it per-vertex by just using the attribute. This is harder to get working with the point size because we need to generate a different vertex shader depending on what attributes are bound. I think if we wanted to make this work transparently we would still want to internally have a pipeline property describing whether the shader was generated with per-vertex support so that it would work with the shader cache correctly. Potentially we could make the per-vertex property internal and automatically make a weak pipeline whenever the attribute is bound. However we would then also need to automatically detect when an application is writing to cogl_point_size_out from a snippet. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 8495d9c1c15ce389885a9356d965eabd97758115) Conflicts: cogl/cogl-context.c cogl/cogl-pipeline-private.h cogl/cogl-pipeline.c cogl/cogl-private.h cogl/driver/gl/cogl-pipeline-progend-fixed.c cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
2012-11-08 16:56:02 +00:00
void
_cogl_pipeline_hash_per_vertex_point_size_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglBool per_vertex_point_size = authority->big_state->per_vertex_point_size;
state->hash = _cogl_util_one_at_a_time_hash (state->hash,
&per_vertex_point_size,
sizeof (per_vertex_point_size));
}
void
_cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state;
state->hash = _cogl_util_one_at_a_time_hash (state->hash, &logic_ops_state->color_mask,
sizeof (CoglColorMask));
}
void
_cogl_pipeline_hash_cull_face_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
CoglPipelineCullFaceState *cull_face_state
= &authority->big_state->cull_face_state;
/* The cull face state is considered equal if two pipelines are both
set to no culling. If the front winding property is ever used for
anything else or the hashing is used not just for drawing then
this would have to change */
if (cull_face_state->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE)
state->hash =
_cogl_util_one_at_a_time_hash (state->hash,
&cull_face_state->mode,
sizeof (CoglPipelineCullFaceMode));
else
state->hash =
_cogl_util_one_at_a_time_hash (state->hash,
cull_face_state,
sizeof (CoglPipelineCullFaceState));
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
void
_cogl_pipeline_hash_uniforms_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
/* This isn't used anywhere yet because the uniform state doesn't
affect program generation. It's quite a hassle to implement so
let's just leave it until something actually needs it */
g_warn_if_reached ();
}
void
_cogl_pipeline_compare_uniform_differences (unsigned long *differences,
CoglPipeline *pipeline0,
CoglPipeline *pipeline1)
{
GSList *head0 = NULL;
GSList *head1 = NULL;
CoglPipeline *node0;
CoglPipeline *node1;
int len0 = 0;
int len1 = 0;
int count;
GSList *common_ancestor0;
GSList *common_ancestor1;
/* This algorithm is copied from
_cogl_pipeline_compare_differences(). It might be nice to share
the code more */
for (node0 = pipeline0; node0; node0 = _cogl_pipeline_get_parent (node0))
{
GSList *link = alloca (sizeof (GSList));
link->next = head0;
link->data = node0;
head0 = link;
len0++;
}
for (node1 = pipeline1; node1; node1 = _cogl_pipeline_get_parent (node1))
{
GSList *link = alloca (sizeof (GSList));
link->next = head1;
link->data = node1;
head1 = link;
len1++;
}
/* NB: There's no point looking at the head entries since we know both
* pipelines must have the same default pipeline as their root node. */
common_ancestor0 = head0;
common_ancestor1 = head1;
head0 = head0->next;
head1 = head1->next;
count = MIN (len0, len1) - 1;
while (count--)
{
if (head0->data != head1->data)
break;
common_ancestor0 = head0;
common_ancestor1 = head1;
head0 = head0->next;
head1 = head1->next;
}
for (head0 = common_ancestor0->next; head0; head0 = head0->next)
{
node0 = head0->data;
if ((node0->differences & COGL_PIPELINE_STATE_UNIFORMS))
{
const CoglPipelineUniformsState *uniforms_state =
&node0->big_state->uniforms_state;
_cogl_bitmask_set_flags (&uniforms_state->override_mask,
differences);
}
}
for (head1 = common_ancestor1->next; head1; head1 = head1->next)
{
node1 = head1->data;
if ((node1->differences & COGL_PIPELINE_STATE_UNIFORMS))
{
const CoglPipelineUniformsState *uniforms_state =
&node1->big_state->uniforms_state;
_cogl_bitmask_set_flags (&uniforms_state->override_mask,
differences);
}
}
}
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
void
_cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
_cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets,
&state->hash);
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
}
void
_cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority,
CoglPipelineHashState *state)
{
_cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets,
&state->hash);
cogl-pipeline: Add two hook points for adding shader snippets This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-17 16:52:21 +00:00
}
UNIT_TEST (check_blend_constant_ancestry,
0 /* no requirements */,
0 /* no known failures */)
{
CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
CoglNode *node;
int pipeline_length = 0;
int i;
/* Repeatedly making a copy of a pipeline and changing the same
* state (in this case the blend constant) shouldn't cause a long
* chain of pipelines to be created because the redundant ancestry
* should be pruned. */
for (i = 0; i < 20; i++)
{
CoglColor color;
CoglPipeline *tmp_pipeline;
cogl_color_init_from_4f (&color, i / 20.0f, 0.0f, 0.0f, 1.0f);
tmp_pipeline = cogl_pipeline_copy (pipeline);
cogl_object_unref (pipeline);
pipeline = tmp_pipeline;
cogl_pipeline_set_blend_constant (pipeline, &color);
}
for (node = (CoglNode *) pipeline; node; node = node->parent)
pipeline_length++;
g_assert_cmpint (pipeline_length, <=, 2);
cogl_object_unref (pipeline);
}
UNIT_TEST (check_uniform_ancestry,
0 /* no requirements */,
TEST_KNOWN_FAILURE)
{
CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
CoglNode *node;
int pipeline_length = 0;
int i;
/* Repeatedly making a copy of a pipeline and changing a uniform
* shouldn't cause a long chain of pipelines to be created */
for (i = 0; i < 20; i++)
{
CoglPipeline *tmp_pipeline;
int uniform_location;
tmp_pipeline = cogl_pipeline_copy (pipeline);
cogl_object_unref (pipeline);
pipeline = tmp_pipeline;
uniform_location =
cogl_pipeline_get_uniform_location (pipeline, "a_uniform");
cogl_pipeline_set_uniform_1i (pipeline, uniform_location, i);
}
for (node = (CoglNode *) pipeline; node; node = node->parent)
pipeline_length++;
g_assert_cmpint (pipeline_length, <=, 2);
cogl_object_unref (pipeline);
}