diff --git a/cogl/cogl-attribute-private.h b/cogl/cogl-attribute-private.h
index a27924b02..d3abcdcee 100644
--- a/cogl/cogl-attribute-private.h
+++ b/cogl/cogl-attribute-private.h
@@ -40,6 +40,7 @@ typedef enum
COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY,
COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY,
COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY,
+ COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY,
COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY
} CoglAttributeNameID;
diff --git a/cogl/cogl-attribute.c b/cogl/cogl-attribute.c
index bc45399ff..49920071e 100644
--- a/cogl/cogl-attribute.c
+++ b/cogl/cogl-attribute.c
@@ -101,6 +101,8 @@ validate_cogl_attribute_name (const char *name,
*name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
*normalized = TRUE;
}
+ else if (strcmp (name, "point_size_in") == 0)
+ *name_id = COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY;
else
{
g_warning ("Unknown cogl_* attribute name cogl_%s\n", name);
@@ -193,6 +195,14 @@ validate_n_components (const CoglAttributeNameState *name_state,
return FALSE;
}
break;
+ case COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY:
+ if (G_UNLIKELY (n_components != 1))
+ {
+ g_critical ("The point size attribute can only have one "
+ "component");
+ return FALSE;
+ }
+ break;
case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
return TRUE;
}
diff --git a/cogl/cogl-attribute.h b/cogl/cogl-attribute.h
index 580446e87..d350833aa 100644
--- a/cogl/cogl-attribute.h
+++ b/cogl/cogl-attribute.h
@@ -76,6 +76,11 @@ COGL_BEGIN_DECLS
* "cogl_tex_coord0_in", "cogl_tex_coord1", ...
* (used for vertex texture coordinates)
* "cogl_normal_in" (used for vertex normals)
+ * "cogl_point_size_in" (used to set the size of points
+ * per-vertex. Note this can only be used if
+ * %COGL_FEATURE_ID_POINT_SIZE_ATTRIBUTE is advertised and
+ * cogl_pipeline_set_per_vertex_point_size() is called on the pipeline.
+ *
*
*
* The attribute values corresponding to different vertices can either
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 96254b926..7365f9172 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -95,6 +95,9 @@ _cogl_init_feature_overrides (CoglContext *ctx)
{
ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL;
COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, FALSE);
+ COGL_FLAGS_SET (ctx->features,
+ COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
+ FALSE);
}
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_NPOT_TEXTURES)))
diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h
index 0dfb5e576..e574bc27a 100644
--- a/cogl/cogl-context.h
+++ b/cogl/cogl-context.h
@@ -214,6 +214,8 @@ cogl_is_context (void *object);
* @COGL_FEATURE_ID_DEPTH_RANGE: cogl_pipeline_set_depth_range() support
* @COGL_FEATURE_ID_POINT_SPRITE: Whether
* cogl_pipeline_set_layer_point_sprite_coords_enabled() is supported.
+ * @COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE: Whether cogl_point_size_in
+ * can be used as an attribute to set a per-vertex point size.
* @COGL_FEATURE_ID_MAP_BUFFER_FOR_READ: Whether cogl_buffer_map() is
* supported with CoglBufferAccess including read support.
* @COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE: Whether cogl_buffer_map() is
@@ -260,6 +262,7 @@ typedef enum _CoglFeatureID
COGL_FEATURE_ID_DEPTH_TEXTURE,
COGL_FEATURE_ID_PRESENTATION_TIME,
COGL_FEATURE_ID_FENCE,
+ COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
/*< private >*/
_COGL_N_FEATURE_IDS /*< skip >*/
diff --git a/cogl/cogl-glsl-shader-boilerplate.h b/cogl/cogl-glsl-shader-boilerplate.h
index 7a79fd335..78762d45c 100644
--- a/cogl/cogl-glsl-shader-boilerplate.h
+++ b/cogl/cogl-glsl-shader-boilerplate.h
@@ -32,8 +32,7 @@
"\n" \
"uniform mat4 cogl_modelview_matrix;\n" \
"uniform mat4 cogl_modelview_projection_matrix;\n" \
- "uniform mat4 cogl_projection_matrix;\n" \
- "uniform float cogl_point_size_in;\n"
+ "uniform mat4 cogl_projection_matrix;\n"
/* This declares all of the variables that we might need. This is
* working on the assumption that the compiler will optimise them out
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 3e385f537..3d8972143 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -118,6 +118,7 @@ typedef enum
COGL_PIPELINE_STATE_DEPTH_INDEX,
COGL_PIPELINE_STATE_FOG_INDEX,
COGL_PIPELINE_STATE_POINT_SIZE_INDEX,
+ COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX,
COGL_PIPELINE_STATE_LOGIC_OPS_INDEX,
COGL_PIPELINE_STATE_CULL_FACE_INDEX,
COGL_PIPELINE_STATE_UNIFORMS_INDEX,
@@ -167,6 +168,8 @@ typedef enum _CoglPipelineState
1L<big_state->point_size == authority1->big_state->point_size;
}
+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)
@@ -1398,6 +1406,63 @@ cogl_pipeline_set_point_size (CoglPipeline *pipeline,
_cogl_pipeline_point_size_equal);
}
+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;
+}
+
static CoglBoxedValue *
_cogl_pipeline_override_uniform (CoglPipeline *pipeline,
int location)
@@ -1832,6 +1897,16 @@ _cogl_pipeline_hash_point_size_state (CoglPipeline *authority,
sizeof (point_size));
}
+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)
diff --git a/cogl/cogl-pipeline-state.h b/cogl/cogl-pipeline-state.h
index 44c50272b..1c68db79d 100644
--- a/cogl/cogl-pipeline-state.h
+++ b/cogl/cogl-pipeline-state.h
@@ -516,6 +516,50 @@ cogl_pipeline_set_point_size (CoglPipeline *pipeline,
float
cogl_pipeline_get_point_size (CoglPipeline *pipeline);
+/**
+ * cogl_pipeline_set_per_vertex_point_size:
+ * @pipeline: a #CoglPipeline pointer
+ * @enable: whether to enable per-vertex point size
+ * @error: a location to store a #CoglError if the change failed
+ *
+ * Sets whether to use a per-vertex point size or to use the value set
+ * by cogl_pipeline_set_point_size(). If per-vertex point size is
+ * enabled then the point size can be set for an individual point
+ * either by drawing with a #CoglAttribute with the name
+ * ‘cogl_point_size_in’ or by writing to the GLSL builtin
+ * ‘cogl_point_size_out’ from a vertex shader snippet.
+ *
+ * If per-vertex point size is enabled and this attribute is not used
+ * and cogl_point_size_out is not written to then the results are
+ * undefined.
+ *
+ * Note that enabling this will only work if the
+ * %COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE feature is available. If
+ * this is not available then the function will return %FALSE and set
+ * a #CoglError.
+ *
+ * Since: 2.0
+ * Stability: Unstable
+ * Return value: %TRUE if the change suceeded or %FALSE otherwise
+ */
+CoglBool
+cogl_pipeline_set_per_vertex_point_size (CoglPipeline *pipeline,
+ CoglBool enable,
+ CoglError **error);
+
+/**
+ * cogl_pipeline_get_per_vertex_point_size:
+ * @pipeline: a #CoglPipeline pointer
+ *
+ * Since: 2.0
+ * Stability: Unstable
+ * Return value: %TRUE if the pipeline has per-vertex point size
+ * enabled or %FALSE otherwise. The per-vertex point size can be
+ * enabled with cogl_pipeline_set_per_vertex_point_size().
+ */
+CoglBool
+cogl_pipeline_get_per_vertex_point_size (CoglPipeline *pipeline);
+
/**
* cogl_pipeline_get_color_mask:
* @pipeline: a #CoglPipeline object.
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 10599668c..dcf459aef 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -1051,6 +1051,9 @@ _cogl_pipeline_copy_differences (CoglPipeline *dest,
if (differences & COGL_PIPELINE_STATE_POINT_SIZE)
big_state->point_size = src->big_state->point_size;
+ if (differences & COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE)
+ big_state->per_vertex_point_size = src->big_state->per_vertex_point_size;
+
if (differences & COGL_PIPELINE_STATE_LOGIC_OPS)
{
memcpy (&big_state->logic_ops_state,
@@ -1134,6 +1137,7 @@ _cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline,
case COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE:
case COGL_PIPELINE_STATE_POINT_SIZE:
case COGL_PIPELINE_STATE_USER_SHADER:
+ case COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE:
case COGL_PIPELINE_STATE_REAL_BLEND_ENABLE:
g_return_if_reached ();
@@ -2319,6 +2323,11 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
authorities1[bit]))
goto done;
break;
+ case COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX:
+ if (!_cogl_pipeline_per_vertex_point_size_equal (authorities0[bit],
+ authorities1[bit]))
+ goto done;
+ break;
case COGL_PIPELINE_STATE_LOGIC_OPS_INDEX:
if (!_cogl_pipeline_logic_ops_state_equal (authorities0[bit],
authorities1[bit]))
@@ -2768,6 +2777,8 @@ _cogl_pipeline_init_state_hash_functions (void)
_cogl_pipeline_hash_cull_face_state;
state_hash_functions[COGL_PIPELINE_STATE_POINT_SIZE_INDEX] =
_cogl_pipeline_hash_point_size_state;
+ state_hash_functions[COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX] =
+ _cogl_pipeline_hash_per_vertex_point_size_state;
state_hash_functions[COGL_PIPELINE_STATE_LOGIC_OPS_INDEX] =
_cogl_pipeline_hash_logic_ops_state;
state_hash_functions[COGL_PIPELINE_STATE_UNIFORMS_INDEX] =
@@ -2779,7 +2790,7 @@ _cogl_pipeline_init_state_hash_functions (void)
{
/* So we get a big error if we forget to update this code! */
- _COGL_STATIC_ASSERT (COGL_PIPELINE_STATE_SPARSE_COUNT == 16,
+ _COGL_STATIC_ASSERT (COGL_PIPELINE_STATE_SPARSE_COUNT == 17,
"Make sure to install a hash function for "
"newly added pipeline state and update assert "
"in _cogl_pipeline_init_state_hash_functions");
diff --git a/cogl/cogl-private.h b/cogl/cogl-private.h
index c17e86531..eb3a3dddd 100644
--- a/cogl/cogl-private.h
+++ b/cogl/cogl-private.h
@@ -61,7 +61,8 @@ typedef enum
/* If this is set then the winsys is responsible for queueing dirty
* events. Otherwise a dirty event will be queued when the onscreen
* is first allocated or when it is shown or resized */
- COGL_PRIVATE_FEATURE_DIRTY_EVENTS = 1L<<25
+ COGL_PRIVATE_FEATURE_DIRTY_EVENTS = 1L<<25,
+ COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE = 1L<<26
} CoglPrivateFeatureFlags;
/* Sometimes when evaluating pipelines, either during comparisons or
diff --git a/cogl/cogl-snippet.h b/cogl/cogl-snippet.h
index 2af31d4ac..e1b30ef8b 100644
--- a/cogl/cogl-snippet.h
+++ b/cogl/cogl-snippet.h
@@ -203,6 +203,16 @@ COGL_BEGIN_DECLS
*
*
* float
+ * cogl_point_size_in
+ *
+ * The incoming point size from the cogl_point_size_in attribute.
+ * This is only available if
+ * cogl_pipeline_set_per_vertex_point_size() is set on the
+ * pipeline.
+ *
+ *
+ *
+ * float
* cogl_point_size_out
*
* The calculated size of a point. This is equivalent to #gl_PointSize.
@@ -321,6 +331,10 @@ typedef struct _CoglSnippet CoglSnippet;
* @COGL_SNIPPET_HOOK_VERTEX: A hook for the entire vertex processing
* stage of the pipeline.
* @COGL_SNIPPET_HOOK_VERTEX_TRANSFORM: A hook for the vertex transformation.
+ * @COGL_SNIPPET_HOOK_POINT_SIZE: A hook for manipulating the point
+ * size of a vertex. This is only used if
+ * cogl_pipeline_set_per_vertex_point_size() is enabled on the
+ * pipeline.
* @COGL_SNIPPET_HOOK_FRAGMENT: A hook for the entire fragment
* processing stage of the pipeline.
* @COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM: A hook for applying the
@@ -422,6 +436,39 @@ typedef struct _CoglSnippet CoglSnippet;
*
*
*
+ * %COGL_SNIPPET_HOOK_POINT_SIZE
+ *
+ *
+ * Adds a shader snippet that will hook on to the point size
+ * calculation step within the vertex shader stage. The snippet should
+ * write to the builtin cogl_point_size_out with the new point size.
+ * The snippet can either read cogl_point_size_in directly and write a
+ * new value or first read an existing value in cogl_point_size_out
+ * that would be set by a previous snippet. Note that this hook is
+ * only used if cogl_pipeline_set_per_vertex_point_size() is enabled
+ * on the pipeline.
+ *
+ *
+ * The ‘declarations’ string in @snippet will be inserted in the
+ * global scope of the shader. Use this to declare any uniforms,
+ * attributes or functions that the snippet requires.
+ *
+ *
+ * The ‘pre’ string in @snippet will be inserted just before
+ * calculating the point size.
+ *
+ *
+ * The ‘replace’ string in @snippet will be used instead of the
+ * generated point size calculation if it is present.
+ *
+ *
+ * The ‘post’ string in @snippet will be inserted after the
+ * standard point size calculation is done. This can be used to modify
+ * cogl_point_size_out in addition to the default processing.
+ *
+ *
+ *
+ *
* %COGL_SNIPPET_HOOK_FRAGMENT
*
*
@@ -583,6 +630,7 @@ typedef enum {
COGL_SNIPPET_HOOK_VERTEX = 0,
COGL_SNIPPET_HOOK_VERTEX_TRANSFORM,
COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
+ COGL_SNIPPET_HOOK_POINT_SIZE,
/* Per pipeline fragment hooks */
COGL_SNIPPET_HOOK_FRAGMENT = 2048,
diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/driver/gl/cogl-pipeline-opengl.c
index 735a45ccd..119b44905 100644
--- a/cogl/driver/gl/cogl-pipeline-opengl.c
+++ b/cogl/driver/gl/cogl-pipeline-opengl.c
@@ -58,7 +58,9 @@
#ifndef GL_CLAMP_TO_BORDER
#define GL_CLAMP_TO_BORDER 0x812d
#endif
-
+#ifndef GL_PROGRAM_POINT_SIZE
+#define GL_PROGRAM_POINT_SIZE 0x8642
+#endif
static void
texture_unit_init (CoglContext *ctx,
@@ -684,6 +686,21 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
}
}
+#ifdef HAVE_COGL_GL
+ if ((ctx->private_feature_flags &
+ COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE) &&
+ (pipelines_difference & COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE))
+ {
+ unsigned long state = COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE;
+ CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, state);
+
+ if (authority->big_state->per_vertex_point_size)
+ GE( ctx, glEnable (GL_PROGRAM_POINT_SIZE) );
+ else
+ GE( ctx, glDisable (GL_PROGRAM_POINT_SIZE) );
+ }
+#endif
+
if (pipeline->real_blend_enable != ctx->gl_blend_enable_cache)
{
if (pipeline->real_blend_enable)
diff --git a/cogl/driver/gl/cogl-pipeline-progend-fixed.c b/cogl/driver/gl/cogl-pipeline-progend-fixed.c
index 78a8c8d3b..558b5b803 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-fixed.c
+++ b/cogl/driver/gl/cogl-pipeline-progend-fixed.c
@@ -64,6 +64,11 @@ _cogl_pipeline_progend_fixed_start (CoglPipeline *pipeline)
if (cogl_pipeline_get_user_program (pipeline))
return FALSE;
+ /* The fixed progend can't handle the per-vertex point size
+ * attribute */
+ if (cogl_pipeline_get_per_vertex_point_size (pipeline))
+ return FALSE;
+
return TRUE;
}
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
index 742346d26..069573a18 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
@@ -290,12 +290,20 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
"cogl_generated_source ()\n"
"{\n");
- if (!(ctx->private_feature_flags &
- COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM))
- /* There is no builtin uniform for the pointsize on GLES2 so we need
- to copy it from the custom uniform in the vertex shader */
- g_string_append (shader_state->source,
- " cogl_point_size_out = cogl_point_size_in;\n");
+ if (cogl_pipeline_get_per_vertex_point_size (pipeline))
+ g_string_append (shader_state->header,
+ "attribute float cogl_point_size_in;\n");
+ else if (!(ctx->private_feature_flags &
+ COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM))
+ {
+ /* There is no builtin uniform for the point size on GLES2 so we
+ need to copy it from the custom uniform in the vertex shader if
+ we're not using per-vertex point sizes */
+ g_string_append (shader_state->header,
+ "uniform float cogl_point_size_in;\n");
+ g_string_append (shader_state->source,
+ " cogl_point_size_out = cogl_point_size_in;\n");
+ }
}
static CoglBool
@@ -389,6 +397,8 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
GLuint shader;
CoglPipelineSnippetData snippet_data;
CoglPipelineSnippetList *vertex_snippets;
+ CoglBool has_per_vertex_point_size =
+ cogl_pipeline_get_per_vertex_point_size (pipeline);
COGL_STATIC_COUNTER (vertend_glsl_compile_counter,
"glsl vertex compile counter",
@@ -407,7 +417,21 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
"}\n");
g_string_append (shader_state->source,
- " cogl_vertex_transform ();\n"
+ " cogl_vertex_transform ();\n");
+
+ if (has_per_vertex_point_size)
+ {
+ g_string_append (shader_state->header,
+ "void\n"
+ "cogl_real_point_size_calculation ()\n"
+ "{\n"
+ " cogl_point_size_out = cogl_point_size_in;\n"
+ "}\n");
+ g_string_append (shader_state->source,
+ " cogl_point_size_calculation ();\n");
+ }
+
+ g_string_append (shader_state->source,
" cogl_color_out = cogl_color_in;\n"
"}\n");
@@ -423,6 +447,19 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
snippet_data.source_buf = shader_state->header;
_cogl_pipeline_snippet_generate_code (&snippet_data);
+ /* Add hooks for the point size calculation part */
+ if (has_per_vertex_point_size)
+ {
+ memset (&snippet_data, 0, sizeof (snippet_data));
+ snippet_data.snippets = vertex_snippets;
+ snippet_data.hook = COGL_SNIPPET_HOOK_POINT_SIZE;
+ snippet_data.chain_function = "cogl_real_point_size_calculation";
+ snippet_data.final_name = "cogl_point_size_calculation";
+ snippet_data.function_prefix = "cogl_point_size_calculation";
+ snippet_data.source_buf = shader_state->header;
+ _cogl_pipeline_snippet_generate_code (&snippet_data);
+ }
+
/* Add all of the hooks for vertex processing */
memset (&snippet_data, 0, sizeof (snippet_data));
snippet_data.snippets = vertex_snippets;
@@ -487,6 +524,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
shader_state->gl_shader = shader;
}
+#ifdef HAVE_COGL_GL
if ((ctx->private_feature_flags &
COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM) &&
(pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE))
@@ -496,6 +534,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
GE( ctx, glPointSize (authority->big_state->point_size) );
}
+#endif /* HAVE_COGL_GL */
return TRUE;
}
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index 25a550c43..6705159ee 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -569,11 +569,23 @@ _cogl_driver_update_features (CoglContext *ctx,
if (ctx->glGenSamplers)
private_flags |= COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS;
+
if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 3) ||
_cogl_check_extension ("GL_ARB_texture_swizzle", gl_extensions) ||
_cogl_check_extension ("GL_EXT_texture_swizzle", gl_extensions))
private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE;
+ /* The per-vertex point size is only available via GLSL with the
+ * gl_PointSize builtin. This is only available in GL 2.0 (not the
+ * GLSL extensions) */
+ if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0))
+ {
+ COGL_FLAGS_SET (ctx->features,
+ COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
+ TRUE);
+ private_flags |= COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE;
+ }
+
if (ctx->driver == COGL_DRIVER_GL)
{
int max_clip_planes = 0;
diff --git a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
index 3975b8dd7..fe46a0d0f 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
+++ b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
@@ -73,6 +73,11 @@ _cogl_pipeline_progend_fixed_arbfp_start (CoglPipeline *pipeline)
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_ARBFP)
return FALSE;
+ /* The ARBfp progend can't handle the per-vertex point size
+ * attribute */
+ if (cogl_pipeline_get_per_vertex_point_size (pipeline))
+ return FALSE;
+
return TRUE;
}
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index f34f0b8a2..bdeaa3078 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -256,6 +256,8 @@ _cogl_driver_update_features (CoglContext *context,
COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE);
COGL_FLAGS_SET (context->features,
COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);
+ COGL_FLAGS_SET (context->features,
+ COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE, TRUE);
private_flags |= COGL_PRIVATE_FEATURE_BLEND_CONSTANT;
}
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
index be5b99a29..be9bfce24 100644
--- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
+++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
@@ -834,6 +834,8 @@ cogl_pipeline_set_blend
cogl_pipeline_set_blend_constant
cogl_pipeline_set_point_size
cogl_pipeline_get_point_size
+cogl_pipeline_set_per_vertex_point_size
+cogl_pipeline_get_per_vertex_point_size
cogl_pipeline_get_color_mask
cogl_pipeline_set_color_mask
diff --git a/examples/cogl-info.c b/examples/cogl-info.c
index 37c964bd7..0eb711e1c 100644
--- a/examples/cogl-info.c
+++ b/examples/cogl-info.c
@@ -115,6 +115,12 @@ struct {
"Depth Textures",
"CoglFramebuffers can be configured to render their depth buffer into "
"a texture"
+ },
+ {
+ COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
+ "Per-vertex point size",
+ "cogl_point_size_in can be used as an attribute to specify a per-vertex "
+ "point size"
}
};
diff --git a/test-fixtures/test-utils.c b/test-fixtures/test-utils.c
index 2c92007cf..5980eeb54 100644
--- a/test-fixtures/test-utils.c
+++ b/test-fixtures/test-utils.c
@@ -49,6 +49,12 @@ check_flags (TestFlags flags,
return FALSE;
}
+ if (flags & TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE))
+ {
+ return FALSE;
+ }
+
if (flags & TEST_REQUIREMENT_GLES2_CONTEXT &&
!cogl_has_feature (test_ctx, COGL_FEATURE_ID_GLES2_CONTEXT))
{
diff --git a/test-fixtures/test-utils.h b/test-fixtures/test-utils.h
index b5ecdd10e..f7cb74874 100644
--- a/test-fixtures/test-utils.h
+++ b/test-fixtures/test-utils.h
@@ -22,7 +22,8 @@ typedef enum _TestFlags
TEST_REQUIREMENT_MAP_WRITE = 1<<7,
TEST_REQUIREMENT_GLSL = 1<<8,
TEST_REQUIREMENT_OFFSCREEN = 1<<9,
- TEST_REQUIREMENT_FENCE = 1<<10
+ TEST_REQUIREMENT_FENCE = 1<<10,
+ TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE = 1<<11
} TestFlags;
extern CoglContext *test_ctx;
diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
index 2f0291ad4..4277aa179 100644
--- a/tests/conform/Makefile.am
+++ b/tests/conform/Makefile.am
@@ -48,6 +48,7 @@ test_sources = \
test-read-texture-formats.c \
test-write-texture-formats.c \
test-point-size.c \
+ test-point-size-attribute.c \
test-point-sprite.c \
test-no-gl-header.c \
test-version.c \
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index 2c776601d..f8124ed35 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -102,6 +102,11 @@ main (int argc, char **argv)
0);
ADD_TEST (test_point_size, 0, 0);
+ ADD_TEST (test_point_size_attribute,
+ TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE, 0);
+ ADD_TEST (test_point_size_attribute_snippet,
+ TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE |
+ TEST_REQUIREMENT_GLSL, 0);
ADD_TEST (test_point_sprite,
TEST_REQUIREMENT_POINT_SPRITE,
0);
diff --git a/tests/conform/test-point-size-attribute.c b/tests/conform/test-point-size-attribute.c
new file mode 100644
index 000000000..81cae95bb
--- /dev/null
+++ b/tests/conform/test-point-size-attribute.c
@@ -0,0 +1,166 @@
+#include
+
+#include "test-utils.h"
+
+/* This test assumes the GL driver supports point sizes up to 16
+ pixels. Cogl should probably have some way of querying the size so
+ we start from that instead */
+#define MAX_POINT_SIZE 16
+#define MIN_POINT_SIZE 4
+#define N_POINTS (MAX_POINT_SIZE - MIN_POINT_SIZE + 1)
+/* The size of the area that we'll paint each point in */
+#define POINT_BOX_SIZE (MAX_POINT_SIZE * 2)
+
+typedef struct
+{
+ float x, y;
+ float point_size;
+} PointVertex;
+
+static int
+calc_coord_offset (int pos, int pos_index, int point_size)
+{
+ switch (pos_index)
+ {
+ case 0: return pos - point_size / 2 - 2;
+ case 1: return pos - point_size / 2 + 2;
+ case 2: return pos + point_size / 2 - 2;
+ case 3: return pos + point_size / 2 + 2;
+ }
+
+ g_assert_not_reached ();
+}
+
+static void
+verify_point_size (CoglFramebuffer *test_fb,
+ int x_pos,
+ int y_pos,
+ int point_size)
+{
+ int y, x;
+
+ for (y = 0; y < 4; y++)
+ for (x = 0; x < 4; x++)
+ {
+ CoglBool in_point = x >= 1 && x <= 2 && y >= 1 && y <= 2;
+ uint32_t expected_pixel = in_point ? 0x00ff00ff : 0xff0000ff;
+
+ test_utils_check_pixel (test_fb,
+ calc_coord_offset (x_pos, x, point_size),
+ calc_coord_offset (y_pos, y, point_size),
+ expected_pixel);
+ }
+}
+
+static CoglPrimitive *
+create_primitive (const char *attribute_name)
+{
+ PointVertex vertices[N_POINTS];
+ CoglAttributeBuffer *buffer;
+ CoglAttribute *attributes[2];
+ CoglPrimitive *prim;
+ int i;
+
+ for (i = 0; i < N_POINTS; i++)
+ {
+ vertices[i].x = i * POINT_BOX_SIZE + POINT_BOX_SIZE / 2;
+ vertices[i].y = POINT_BOX_SIZE / 2;
+ vertices[i].point_size = MAX_POINT_SIZE - i;
+ }
+
+ buffer = cogl_attribute_buffer_new (test_ctx,
+ sizeof (vertices),
+ vertices);
+
+ attributes[0] = cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (PointVertex),
+ G_STRUCT_OFFSET (PointVertex, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ attributes[1] = cogl_attribute_new (buffer,
+ attribute_name,
+ sizeof (PointVertex),
+ G_STRUCT_OFFSET (PointVertex, point_size),
+ 1, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+
+ prim = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_POINTS,
+ N_POINTS,
+ attributes,
+ 2 /* n_attributes */);
+
+ for (i = 0; i < 2; i++)
+ cogl_object_unref (attributes[i]);
+
+ return prim;
+}
+
+static void
+do_test (const char *attribute_name,
+ void (* pipeline_setup_func) (CoglPipeline *pipeline))
+{
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ CoglPrimitive *primitive;
+ CoglPipeline *pipeline;
+ int i;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, /* x_1, y_1 */
+ fb_width, /* x_2 */
+ fb_height /* y_2 */,
+ -1, 100 /* near/far */);
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 1.0f, 0.0f, 0.0f, 1.0f);
+
+ primitive = create_primitive (attribute_name);
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_color4ub (pipeline, 0x00, 0xff, 0x00, 0xff);
+ cogl_pipeline_set_per_vertex_point_size (pipeline, TRUE, NULL);
+ if (pipeline_setup_func)
+ pipeline_setup_func (pipeline);
+ cogl_framebuffer_draw_primitive (test_fb, pipeline, primitive);
+ cogl_object_unref (pipeline);
+ cogl_object_unref (primitive);
+
+ /* Verify all of the points where drawn at the right size */
+ for (i = 0; i < N_POINTS; i++)
+ verify_point_size (test_fb,
+ i * POINT_BOX_SIZE + POINT_BOX_SIZE / 2, /* x */
+ POINT_BOX_SIZE / 2, /* y */
+ MAX_POINT_SIZE - i /* point size */);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
+void
+test_point_size_attribute (void)
+{
+ do_test ("cogl_point_size_in", NULL);
+}
+
+static void
+setup_snippet (CoglPipeline *pipeline)
+{
+ CoglSnippet *snippet;
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_POINT_SIZE,
+ "attribute float "
+ "my_super_duper_point_size_attrib;\n",
+ NULL);
+ cogl_snippet_set_replace (snippet,
+ "cogl_point_size_out = "
+ "my_super_duper_point_size_attrib;\n");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+}
+
+void
+test_point_size_attribute_snippet (void)
+{
+ do_test ("my_super_duper_point_size_attrib", setup_snippet);
+}