summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2011-11-03 17:28:01 +0000
committerNeil Roberts <neil@linux.intel.com>2011-11-16 16:32:11 +0000
commit8805d835aa6cd22a19635749324ba54c63a60811 (patch)
tree591fcfe566626d6cfaf0a3ce52d7e3c8061a6ff6
parent4553ca0695a08a08a32925d3621d4269b6c459c7 (diff)
downloadcogl-8805d835aa6cd22a19635749324ba54c63a60811.tar.gz
Add a conformance test for setting uniforms on a pipeline
The tests tries all of the various combinations of setting uniform values on a pipeline and verifies the expected results with a some example shaders. Reviewed-by: Robert Bragg <robert@linux.intel.com>
-rw-r--r--tests/conform/Makefile.am1
-rw-r--r--tests/conform/test-conform-main.c1
-rw-r--r--tests/conform/test-pipeline-uniforms.c428
3 files changed, 430 insertions, 0 deletions
diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
index 4f329910..912f1681 100644
--- a/tests/conform/Makefile.am
+++ b/tests/conform/Makefile.am
@@ -42,6 +42,7 @@ test_sources = \
test-just-vertex-shader.c \
test-path.c \
test-pipeline-user-matrix.c \
+ test-pipeline-uniforms.c \
test-wrap-modes.c \
test-sub-texture.c \
$(NULL)
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index ecb4bb20..5be834b6 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -161,6 +161,7 @@ main (int argc, char **argv)
UNPORTED_TEST ("/cogl/vertex-array", test_cogl_primitive);
ADD_TEST ("/cogl/shaders", test_cogl_just_vertex_shader);
+ ADD_TEST ("/cogl/shaders", test_cogl_pipeline_uniforms);
ADD_TEST ("/cogl/internal/bitmask", test_cogl_bitmask);
diff --git a/tests/conform/test-pipeline-uniforms.c b/tests/conform/test-pipeline-uniforms.c
new file mode 100644
index 00000000..8908bf72
--- /dev/null
+++ b/tests/conform/test-pipeline-uniforms.c
@@ -0,0 +1,428 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define LONG_ARRAY_SIZE 128
+
+typedef struct _TestState
+{
+ CoglPipeline *pipeline_red;
+ CoglPipeline *pipeline_green;
+ CoglPipeline *pipeline_blue;
+
+ CoglPipeline *matrix_pipeline;
+ CoglPipeline *vector_pipeline;
+ CoglPipeline *int_pipeline;
+
+ CoglPipeline *long_pipeline;
+ int long_uniform_locations[LONG_ARRAY_SIZE];
+} TestState;
+
+static const char
+color_source[] =
+ "uniform float red, green, blue;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = vec4 (red, green, blue, 1.0);\n"
+ "}\n";
+
+static const char
+matrix_source[] =
+ "uniform mat4 matrix_array[4];\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " vec4 color = vec4 (0.0, 0.0, 0.0, 1.0);\n"
+ " int i;\n"
+ "\n"
+ " for (i = 0; i < 4; i++)\n"
+ " color = matrix_array[i] * color;\n"
+ "\n"
+ " cogl_color_out = color;\n"
+ "}\n";
+
+static const char
+vector_source[] =
+ "uniform vec4 vector_array[2];\n"
+ "uniform vec3 short_vector;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = (vector_array[0] +\n"
+ " vector_array[1] +\n"
+ " vec4 (short_vector, 1.0));\n"
+ "}\n";
+
+static const char
+int_source[] =
+ "uniform ivec4 vector_array[2];\n"
+ "uniform int single_value;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = (vec4 (vector_array[0]) +\n"
+ " vec4 (vector_array[1]) +\n"
+ " vec4 (float (single_value), 0.0, 0.0, 255.0)) / 255.0;\n"
+ "}\n";
+
+static const char
+long_source[] =
+ "uniform int long_array[" G_STRINGIFY (LONG_ARRAY_SIZE) "];\n"
+ "const int last_index = " G_STRINGIFY (LONG_ARRAY_SIZE) " - 1;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = vec4 (float (long_array[last_index]), 0.0, 0.0, 1.0);\n"
+ "}\n";
+
+static CoglPipeline *
+create_pipeline_for_shader (const char *shader_source)
+{
+ CoglPipeline *pipeline;
+ CoglHandle shader;
+ CoglHandle program;
+
+ pipeline = cogl_pipeline_new ();
+
+ shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
+ cogl_shader_source (shader, shader_source);
+
+ program = cogl_create_program ();
+ cogl_program_attach_shader (program, shader);
+
+ cogl_pipeline_set_user_program (pipeline, program);
+
+ cogl_handle_unref (shader);
+ cogl_handle_unref (program);
+
+ return pipeline;
+}
+
+static void
+init_state (TestState *state)
+{
+ int uniform_location;
+
+ state->pipeline_red = create_pipeline_for_shader (color_source);
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_red, "red");
+ cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 1.0f);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_red, "green");
+ cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_red, "blue");
+ cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f);
+
+ state->pipeline_green = cogl_pipeline_copy (state->pipeline_red);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_green, "green");
+ cogl_pipeline_set_uniform_1f (state->pipeline_green, uniform_location, 1.0f);
+
+ state->pipeline_blue = cogl_pipeline_copy (state->pipeline_red);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_blue, "blue");
+ cogl_pipeline_set_uniform_1f (state->pipeline_blue, uniform_location, 1.0f);
+
+ state->matrix_pipeline = create_pipeline_for_shader (matrix_source);
+ state->vector_pipeline = create_pipeline_for_shader (vector_source);
+ state->int_pipeline = create_pipeline_for_shader (int_source);
+
+ state->long_pipeline = NULL;
+}
+
+static void
+init_long_pipeline_state (TestState *state)
+{
+ int i;
+
+ state->long_pipeline = create_pipeline_for_shader (long_source);
+
+ /* This tries to lookup a large number of uniform names to make sure
+ that the bitmask of overriden uniforms flows over the size of a
+ single long so that it has to resort to allocating it */
+ for (i = 0; i < LONG_ARRAY_SIZE; i++)
+ {
+ char *uniform_name = g_strdup_printf ("long_array[%i]", i);
+ state->long_uniform_locations[i] =
+ cogl_pipeline_get_uniform_location (state->long_pipeline,
+ uniform_name);
+ g_free (uniform_name);
+ }
+}
+
+static void
+destroy_state (TestState *state)
+{
+ cogl_object_unref (state->pipeline_red);
+ cogl_object_unref (state->pipeline_green);
+ cogl_object_unref (state->pipeline_blue);
+ cogl_object_unref (state->matrix_pipeline);
+ cogl_object_unref (state->vector_pipeline);
+ cogl_object_unref (state->int_pipeline);
+
+ if (state->long_pipeline)
+ cogl_object_unref (state->long_pipeline);
+}
+
+static void
+paint_pipeline (CoglPipeline *pipeline, int pos)
+{
+ cogl_push_source (pipeline);
+ cogl_rectangle (pos * 10, 0, pos * 10 + 10, 10);
+ cogl_pop_source ();
+}
+
+static void
+paint_color_pipelines (TestState *state)
+{
+ CoglPipeline *temp_pipeline;
+ int uniform_location;
+ int i;
+
+ /* Paint with the first pipeline that sets the uniforms to bright
+ red */
+ paint_pipeline (state->pipeline_red, 0);
+
+ /* Paint with the two other pipelines. These inherit from the red
+ pipeline and only override one other component. The values for
+ the two other components should be inherited from the red
+ pipeline. */
+ paint_pipeline (state->pipeline_green, 1);
+ paint_pipeline (state->pipeline_blue, 2);
+
+ /* Try modifying a single pipeline for multiple rectangles */
+ temp_pipeline = cogl_pipeline_copy (state->pipeline_green);
+ uniform_location = cogl_pipeline_get_uniform_location (temp_pipeline,
+ "green");
+
+ for (i = 0; i <= 8; i++)
+ {
+ cogl_pipeline_set_uniform_1f (temp_pipeline, uniform_location,
+ i / 8.0f);
+ paint_pipeline (temp_pipeline, i + 3);
+ }
+
+ cogl_object_unref (temp_pipeline);
+}
+
+static void
+paint_matrix_pipeline (CoglPipeline *pipeline)
+{
+ CoglMatrix matrices[4];
+ float matrix_floats[16 * 4];
+ int uniform_location;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ cogl_matrix_init_identity (matrices + i);
+
+ /* Use the first matrix to make the color red */
+ cogl_matrix_translate (matrices + 0, 1.0f, 0.0f, 0.0f);
+
+ /* Rotate the vertex so that it ends up green */
+ cogl_matrix_rotate (matrices + 1, 90.0f, 0.0f, 0.0f, 1.0f);
+
+ /* Scale the vertex so it ends up halved */
+ cogl_matrix_scale (matrices + 2, 0.5f, 0.5f, 0.5f);
+
+ /* Add a blue component in the final matrix. The final matrix is
+ uploaded as transposed so we need to transpose first to cancel
+ that out */
+ cogl_matrix_translate (matrices + 3, 0.0f, 0.0f, 1.0f);
+ cogl_matrix_transpose (matrices + 3);
+
+ for (i = 0; i < 4; i++)
+ memcpy (matrix_floats + i * 16,
+ cogl_matrix_get_array (matrices + i),
+ sizeof (float) * 16);
+
+ /* Set the first three matrices as transposed */
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "matrix_array");
+ cogl_pipeline_set_uniform_matrix (pipeline,
+ uniform_location,
+ 4, /* dimensions */
+ 3, /* count */
+ FALSE, /* not transposed */
+ matrix_floats);
+
+ /* Set the last matrix as untransposed */
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "matrix_array[3]");
+ cogl_pipeline_set_uniform_matrix (pipeline,
+ uniform_location,
+ 4, /* dimensions */
+ 1, /* count */
+ TRUE, /* transposed */
+ matrix_floats + 16 * 3);
+
+ paint_pipeline (pipeline, 12);
+}
+
+static void
+paint_vector_pipeline (CoglPipeline *pipeline)
+{
+ float vector_array_values[] = { 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f };
+ float short_vector_values[] = { 0.0f, 0.0f, 1.0f };
+ int uniform_location;
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "vector_array");
+ cogl_pipeline_set_uniform_float (pipeline,
+ uniform_location,
+ 4, /* n_components */
+ 2, /* count */
+ vector_array_values);
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "short_vector");
+ cogl_pipeline_set_uniform_float (pipeline,
+ uniform_location,
+ 3, /* n_components */
+ 1, /* count */
+ short_vector_values);
+
+ paint_pipeline (pipeline, 13);
+}
+
+static void
+paint_int_pipeline (CoglPipeline *pipeline)
+{
+ int vector_array_values[] = { 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00 };
+ int single_value = 0x80;
+ int uniform_location;
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "vector_array");
+ cogl_pipeline_set_uniform_int (pipeline,
+ uniform_location,
+ 4, /* n_components */
+ 2, /* count */
+ vector_array_values);
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "single_value");
+ cogl_pipeline_set_uniform_1i (pipeline,
+ uniform_location,
+ single_value);
+
+ paint_pipeline (pipeline, 14);
+}
+
+static void
+paint_long_pipeline (TestState *state)
+{
+ int i;
+
+ for (i = 0; i < LONG_ARRAY_SIZE; i++)
+ {
+ int location = state->long_uniform_locations[i];
+
+ cogl_pipeline_set_uniform_1i (state->long_pipeline,
+ location,
+ i == LONG_ARRAY_SIZE - 1);
+ }
+
+ paint_pipeline (state->long_pipeline, 15);
+}
+
+static void
+paint (TestState *state)
+{
+ CoglColor color;
+
+ cogl_color_init_from_4ub (&color, 0, 0, 0, 255);
+ cogl_clear (&color, COGL_BUFFER_BIT_COLOR);
+
+ paint_color_pipelines (state);
+ paint_matrix_pipeline (state->matrix_pipeline);
+ paint_vector_pipeline (state->vector_pipeline);
+ paint_int_pipeline (state->int_pipeline);
+}
+
+static void
+check_pos (int pos, guint32 color)
+{
+ test_utils_check_pixel (pos * 10 + 5, 5, color);
+}
+
+static void
+validate_result (void)
+{
+ int i;
+
+ check_pos (0, 0xff0000ff);
+ check_pos (1, 0xffff00ff);
+ check_pos (2, 0xff00ffff);
+
+ for (i = 0; i <= 8; i++)
+ {
+ int green_value = i / 8.0f * 255.0f + 0.5f;
+ check_pos (i + 3, 0xff0000ff + (green_value << 16));
+ }
+
+ check_pos (12, 0x0080ffff);
+ check_pos (13, 0xffffffff);
+ check_pos (14, 0x80ffffff);
+}
+
+static void
+validate_long_pipeline_result (void)
+{
+ check_pos (15, 0xff0000ff);
+}
+
+void
+test_cogl_pipeline_uniforms (TestUtilsGTestFixture *fixture,
+ void *user_data)
+{
+ TestUtilsSharedState *shared_state = user_data;
+
+ /* If shaders aren't supported then we can't run the test */
+ if (cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
+ {
+ TestState state;
+
+ init_state (&state);
+
+ cogl_ortho (/* left, right */
+ 0, cogl_framebuffer_get_width (shared_state->fb),
+ /* bottom, top */
+ cogl_framebuffer_get_height (shared_state->fb), 0,
+ /* z near, far */
+ -1, 100);
+
+ paint (&state);
+ validate_result ();
+
+ /* Try the test again after querying the location of a large
+ number of uniforms. This should verify that the bitmasks
+ still work even if they have to allocate a separate array to
+ store the bits */
+
+ init_long_pipeline_state (&state);
+ paint (&state);
+ paint_long_pipeline (&state);
+ validate_result ();
+ validate_long_pipeline_result ();
+
+ destroy_state (&state);
+
+ if (g_test_verbose ())
+ g_print ("OK\n");
+ }
+ else if (g_test_verbose ())
+ g_print ("Skipping\n");
+}