[Cogl] [PATCH 6/8] test-gles2-context: Add a test case for rendering to an FBO

Robert Bragg robert at sixbynine.org
Thu Aug 9 10:53:47 PDT 2012


This looks good to land to me:

Reviewed-by: Robert Bragg <robert at linux.intel.com>

thanks,
- Robert

On Thu, Aug 9, 2012 at 5:08 PM, Neil Roberts <neil at linux.intel.com> wrote:
> This adds an extra test to test-gles2-context which renders to an FBO
> and then checks that the orientation is correct once the texture is
> rendered via Cogl. This should test the code path to flip the GLES2
> rendering in Cogl.
>
> The rendering is done in three different ways to test the various
> state that needs flipping:
>
> • Just renders two triangle strips, one at the top and one at the
>   bottom.
>
> • Renders two full screen triangle strips, but each with a different
>   viewport to clip it to the top or the bottom.
>
> • Clears the screen with two different colors and a scissor to either
>   the top or the bottom.
>
> • Renders both quads twice with two different colors and two different
>   front face states.
>
> Additionally the rendering is verified by calling glReadPixels to
> check that the returned pixels are flipped correctly.
> ---
>  tests/conform/test-conform-main.c  |   1 +
>  tests/conform/test-gles2-context.c | 359 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 360 insertions(+)
>
> diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
> index fc49635..a9d7d6a 100644
> --- a/tests/conform/test-conform-main.c
> +++ b/tests/conform/test-conform-main.c
> @@ -103,6 +103,7 @@ main (int argc, char **argv)
>    UNPORTED_TEST (test_viewport);
>
>    ADD_TEST (test_gles2_context, TEST_REQUIREMENT_GLES2_CONTEXT);
> +  ADD_TEST (test_gles2_context_fbo, TEST_REQUIREMENT_GLES2_CONTEXT);
>
>    ADD_TEST (test_euler_quaternion, 0);
>
> diff --git a/tests/conform/test-gles2-context.c b/tests/conform/test-gles2-context.c
> index fdb796f..f9d0175 100644
> --- a/tests/conform/test-gles2-context.c
> +++ b/tests/conform/test-gles2-context.c
> @@ -384,3 +384,362 @@ test_gles2_context (void)
>    if (cogl_test_verbose ())
>      g_print ("OK\n");
>  }
> +
> +static GLuint
> +create_shader (const CoglGLES2Vtable *gles2,
> +               GLenum type,
> +               const char *source)
> +{
> +  GLuint shader;
> +  GLint status;
> +  int length = strlen (source);
> +
> +  shader = gles2->glCreateShader (type);
> +  gles2->glShaderSource (shader, 1, &source, &length);
> +  gles2->glCompileShader (shader);
> +  gles2->glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
> +
> +  if (!status)
> +    {
> +      char buf[512];
> +
> +      gles2->glGetShaderInfoLog (shader, sizeof (buf), NULL, buf);
> +
> +      g_error ("Shader compilation failed:\n%s", buf);
> +    }
> +
> +  return shader;
> +}
> +
> +static GLuint
> +create_program (const CoglGLES2Vtable *gles2,
> +                const char *vertex_shader_source,
> +                const char *fragment_shader_source)
> +{
> +  GLuint fragment_shader, vertex_shader, program;
> +  GLint status;
> +
> +  vertex_shader =
> +    create_shader (gles2, GL_VERTEX_SHADER, vertex_shader_source);
> +  fragment_shader =
> +    create_shader (gles2, GL_FRAGMENT_SHADER, fragment_shader_source);
> +
> +  program = gles2->glCreateProgram ();
> +  gles2->glAttachShader (program, vertex_shader);
> +  gles2->glAttachShader (program, fragment_shader);
> +  gles2->glLinkProgram (program);
> +
> +  gles2->glGetProgramiv (program, GL_LINK_STATUS, &status);
> +
> +  if (!status)
> +    {
> +      char buf[512];
> +
> +      gles2->glGetProgramInfoLog (program, sizeof (buf), NULL, buf);
> +
> +      g_error ("Program linking failed:\n%s", buf);
> +    }
> +
> +  return program;
> +}
> +
> +typedef struct
> +{
> +  const CoglGLES2Vtable *gles2;
> +  GLint color_location;
> +  GLint pos_location;
> +  int fb_width, fb_height;
> +} PaintData;
> +
> +typedef void (* PaintMethod) (PaintData *data);
> +
> +/* Top vertices are counter-clockwise */
> +static const float top_vertices[] =
> +  {
> +    -1.0f, 0.0f,
> +    1.0f, 0.0f,
> +    -1.0f, 1.0f,
> +    1.0f, 1.0f
> +  };
> +/* Bottom vertices are clockwise */
> +static const float bottom_vertices[] =
> +  {
> +    1.0f, 0.0f,
> +    1.0f, -1.0f,
> +    -1.0f, 0.0f,
> +    -1.0f, -1.0f
> +  };
> +
> +static void
> +paint_quads (PaintData *data)
> +{
> +  const CoglGLES2Vtable *gles2 = data->gles2;
> +
> +  gles2->glEnableVertexAttribArray (data->pos_location);
> +
> +  /* Paint the top half in red */
> +  gles2->glUniform4f (data->color_location,
> +                      1.0f, 0.0f, 0.0f, 1.0f);
> +  gles2->glVertexAttribPointer (data->pos_location,
> +                                2, /* size */
> +                                GL_FLOAT,
> +                                GL_FALSE, /* not normalized */
> +                                sizeof (float) * 2,
> +                                top_vertices);
> +  gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
> +
> +  /* Paint the bottom half in blue */
> +  gles2->glUniform4f (data->color_location,
> +                      0.0f, 0.0f, 1.0f, 1.0f);
> +  gles2->glVertexAttribPointer (data->pos_location,
> +                                2, /* size */
> +                                GL_FLOAT,
> +                                GL_FALSE, /* not normalized */
> +                                sizeof (float) * 2,
> +                                bottom_vertices);
> +  gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
> +}
> +
> +static void
> +paint_viewport (PaintData *data)
> +{
> +  const CoglGLES2Vtable *gles2 = data->gles2;
> +  int viewport[4];
> +
> +  /* Vertices to fill the entire framebuffer */
> +  static const float vertices[] =
> +    {
> +      -1.0f, -1.0f,
> +      1.0f, -1.0f,
> +      -1.0f, 1.0f,
> +      1.0f, 1.0f
> +    };
> +
> +  gles2->glEnableVertexAttribArray (data->pos_location);
> +  gles2->glVertexAttribPointer (data->pos_location,
> +                                2, /* size */
> +                                GL_FLOAT,
> +                                GL_FALSE, /* not normalized */
> +                                sizeof (float) * 2,
> +                                vertices);
> +
> +  /* Paint the top half in red */
> +  gles2->glViewport (0, data->fb_height / 2,
> +                     data->fb_width, data->fb_height / 2);
> +  gles2->glUniform4f (data->color_location,
> +                      1.0f, 0.0f, 0.0f, 1.0f);
> +  gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
> +
> +  /* Paint the bottom half in blue */
> +  gles2->glViewport (0, 0, data->fb_width, data->fb_height / 2);
> +  gles2->glUniform4f (data->color_location,
> +                      0.0f, 0.0f, 1.0f, 1.0f);
> +  gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
> +
> +  gles2->glGetIntegerv (GL_VIEWPORT, viewport);
> +  g_assert_cmpint (viewport[0], ==, 0.0f);
> +  g_assert_cmpint (viewport[1], ==, 0.0f);
> +  g_assert_cmpint (viewport[2], ==, data->fb_width);
> +  g_assert_cmpint (viewport[3], ==, data->fb_height / 2);
> +}
> +
> +static void
> +paint_scissor (PaintData *data)
> +{
> +  const CoglGLES2Vtable *gles2 = data->gles2;
> +  float scissor[4];
> +
> +  gles2->glEnable (GL_SCISSOR_TEST);
> +
> +  /* Paint the top half in red */
> +  gles2->glScissor (0, data->fb_height / 2,
> +                    data->fb_width, data->fb_height / 2);
> +  gles2->glClearColor (1.0, 0.0, 0.0, 1.0);
> +  gles2->glClear (GL_COLOR_BUFFER_BIT);
> +
> +  /* Paint the bottom half in blue */
> +  gles2->glScissor (0, 0, data->fb_width, data->fb_height / 2);
> +  gles2->glClearColor (0.0, 0.0, 1.0, 1.0);
> +  gles2->glClear (GL_COLOR_BUFFER_BIT);
> +
> +  gles2->glGetFloatv (GL_SCISSOR_BOX, scissor);
> +  g_assert_cmpfloat (scissor[0], ==, 0.0f);
> +  g_assert_cmpfloat (scissor[1], ==, 0.0f);
> +  g_assert_cmpfloat (scissor[2], ==, data->fb_width);
> +  g_assert_cmpfloat (scissor[3], ==, data->fb_height / 2);
> +}
> +
> +static void
> +paint_cull (PaintData *data)
> +{
> +  const CoglGLES2Vtable *gles2 = data->gles2;
> +  GLint front_face;
> +  int i;
> +
> +  gles2->glEnableVertexAttribArray (data->pos_location);
> +  gles2->glEnable (GL_CULL_FACE);
> +
> +  /* First time round we'll use GL_CCW as the front face so that the
> +   * bottom quad will be culled */
> +  gles2->glFrontFace (GL_CCW);
> +  gles2->glUniform4f (data->color_location,
> +                      1.0f, 0.0f, 0.0f, 1.0f);
> +
> +  gles2->glGetIntegerv (GL_FRONT_FACE, &front_face);
> +  g_assert_cmpint (front_face, ==, GL_CCW);
> +
> +  for (i = 0; i < 2; i++)
> +    {
> +      /* Paint both quads in the same color. One of these will be
> +       * culled */
> +      gles2->glVertexAttribPointer (data->pos_location,
> +                                    2, /* size */
> +                                    GL_FLOAT,
> +                                    GL_FALSE, /* not normalized */
> +                                    sizeof (float) * 2,
> +                                    top_vertices);
> +      gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
> +
> +      gles2->glVertexAttribPointer (data->pos_location,
> +                                    2, /* size */
> +                                    GL_FLOAT,
> +                                    GL_FALSE, /* not normalized */
> +                                    sizeof (float) * 2,
> +                                    bottom_vertices);
> +      gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
> +
> +      /* Second time round we'll use GL_CW as the front face so that the
> +       * top quad will be culled */
> +      gles2->glFrontFace (GL_CW);
> +      gles2->glUniform4f (data->color_location,
> +                          0.0f, 0.0f, 1.0f, 1.0f);
> +
> +      gles2->glGetIntegerv (GL_FRONT_FACE, &front_face);
> +      g_assert_cmpint (front_face, ==, GL_CW);
> +    }
> +}
> +
> +static void
> +verify_read_pixels (const PaintData *data)
> +{
> +  int stride = data->fb_width * 4;
> +  uint8_t *buf = g_malloc (data->fb_height * stride);
> +
> +  data->gles2->glReadPixels (0, 0, /* x/y */
> +                             data->fb_width, data->fb_height,
> +                             GL_RGBA,
> +                             GL_UNSIGNED_BYTE,
> +                             buf);
> +
> +  /* In GL, the lines earlier in the buffer are the bottom */
> +  /* Bottom should be blue */
> +  test_utils_compare_pixel (buf + data->fb_width / 2 * 4 +
> +                            data->fb_height / 4 * stride,
> +                            0x0000ffff);
> +  /* Top should be red */
> +  test_utils_compare_pixel (buf + data->fb_width / 2 * 4 +
> +                            data->fb_height * 3 / 4 * stride,
> +                            0xff0000ff);
> +
> +  g_free (buf);
> +}
> +
> +void
> +test_gles2_context_fbo (void)
> +{
> +  static const char vertex_shader_source[] =
> +    "attribute vec2 pos;\n"
> +    "\n"
> +    "void\n"
> +    "main ()\n"
> +    "{\n"
> +    "  gl_Position = vec4 (pos, 0.0, 1.0);\n"
> +    "}\n";
> +  static const char fragment_shader_source[] =
> +    "precision mediump float;\n"
> +    "uniform vec4 color;\n"
> +    "\n"
> +    "void\n"
> +    "main ()\n"
> +    "{\n"
> +    "  gl_FragColor = color;\n"
> +    "}\n";
> +  static const PaintMethod paint_methods[] =
> +    {
> +      paint_quads,
> +      paint_viewport,
> +      paint_scissor,
> +      paint_cull
> +    };
> +  int i;
> +  PaintData data;
> +
> +  data.fb_width = cogl_framebuffer_get_width (test_fb);
> +  data.fb_height = cogl_framebuffer_get_height (test_fb);
> +
> +  for (i = 0; i < G_N_ELEMENTS (paint_methods); i++)
> +    {
> +      CoglTexture *offscreen_texture;
> +      CoglOffscreen *offscreen;
> +      CoglPipeline *pipeline;
> +      CoglGLES2Context *gles2_ctx;
> +      GLuint program;
> +      GError *error = NULL;
> +
> +      create_gles2_context (&offscreen_texture,
> +                            &offscreen,
> +                            &pipeline,
> +                            &gles2_ctx,
> +                            &data.gles2);
> +
> +      if (!cogl_push_gles2_context (test_ctx,
> +                                    gles2_ctx,
> +                                    COGL_FRAMEBUFFER (offscreen),
> +                                    COGL_FRAMEBUFFER (offscreen),
> +                                    &error))
> +        g_error ("Failed to push gles2 context: %s\n", error->message);
> +
> +      program = create_program (data.gles2,
> +                                vertex_shader_source,
> +                                fragment_shader_source);
> +
> +      data.gles2->glClearColor (1.0, 1.0, 0.0, 1.0);
> +      data.gles2->glClear (GL_COLOR_BUFFER_BIT);
> +
> +      data.gles2->glUseProgram (program);
> +
> +      data.color_location = data.gles2->glGetUniformLocation (program, "color");
> +      if (data.color_location == -1)
> +        g_error ("Couldn't find ‘color’ uniform");
> +
> +      data.pos_location = data.gles2->glGetAttribLocation (program, "pos");
> +      if (data.pos_location == -1)
> +        g_error ("Couldn't find ‘pos’ attribute");
> +
> +      paint_methods[i] (&data);
> +
> +      verify_read_pixels (&data);
> +
> +      cogl_pop_gles2_context (test_ctx);
> +
> +      cogl_object_unref (offscreen);
> +      cogl_object_unref (gles2_ctx);
> +
> +      cogl_framebuffer_draw_rectangle (test_fb,
> +                                       pipeline,
> +                                       -1.0f, 1.0f,
> +                                       1.0f, -1.0f);
> +
> +      cogl_object_unref (pipeline);
> +      cogl_object_unref (offscreen_texture);
> +
> +      /* Top half of the framebuffer should be red */
> +      test_utils_check_pixel (test_fb,
> +                              data.fb_width / 2, data.fb_height / 4,
> +                              0xff0000ff);
> +      /* Bottom half should be blue */
> +      test_utils_check_pixel (test_fb,
> +                              data.fb_width / 2, data.fb_height * 3 / 4,
> +                              0x0000ffff);
> +    }
> +}
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl


More information about the Cogl mailing list