[Cogl] [PATCH v2 4/5] conform: Adds a gles2 context test

Robert Bragg robert at sixbynine.org
Mon May 14 15:02:20 PDT 2012


From: Robert Bragg <robert at linux.intel.com>

This adds a conformance test that creates a GLES2 context via the cogl
api and verifies clearing an offscreen framebuffer via the gles2 api,
and switching back and forth between the Cogl and GLES2 apis.
---
 tests/conform/Makefile.am          |    1 +
 tests/conform/test-conform-main.c  |    2 +
 tests/conform/test-gles2-context.c |  385 ++++++++++++++++++++++++++++++++++++
 3 files changed, 388 insertions(+), 0 deletions(-)
 create mode 100644 tests/conform/test-gles2-context.c

diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
index 8379fe6..81931fd 100644
--- a/tests/conform/Makefile.am
+++ b/tests/conform/Makefile.am
@@ -54,6 +54,7 @@ test_sources = \
 	test-point-sprite.c \
 	test-no-gl-header.c \
 	test-version.c \
+	test-gles2-context.c \
 	$(NULL)
 
 test_conformance_SOURCES = $(common_sources) $(test_sources)
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index bb1c48c..7702791 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -99,6 +99,8 @@ main (int argc, char **argv)
 
   UNPORTED_TEST (test_viewport);
 
+  ADD_TEST (test_gles2_context, 0);
+
   g_printerr ("Unknown test name \"%s\"\n", argv[1]);
 
   return 1;
diff --git a/tests/conform/test-gles2-context.c b/tests/conform/test-gles2-context.c
new file mode 100644
index 0000000..cde2adf
--- /dev/null
+++ b/tests/conform/test-gles2-context.c
@@ -0,0 +1,385 @@
+
+#include <cogl/cogl.h>
+#include <cogl/cogl-gles2.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+  CoglTexture *offscreen_texture;
+  CoglOffscreen *offscreen;
+  CoglGLES2Context *gles2_ctx;
+  const CoglGLES2Vtable *gles2;
+} TestState;
+
+static void
+test_push_pop_single_context (void)
+{
+  CoglTexture *offscreen_texture;
+  CoglOffscreen *offscreen;
+  CoglPipeline *pipeline;
+  CoglGLES2Context *gles2_ctx;
+  const CoglGLES2Vtable *gles2;
+  GError *error = NULL;
+
+  offscreen_texture = COGL_TEXTURE (
+    cogl_texture_2d_new_with_size (test_ctx,
+                                   cogl_framebuffer_get_width (test_fb),
+                                   cogl_framebuffer_get_height (test_fb),
+                                   COGL_PIXEL_FORMAT_ANY,
+                                   NULL));
+  offscreen = cogl_offscreen_new_to_texture (offscreen_texture);
+
+  pipeline = cogl_pipeline_new (test_ctx);
+  cogl_pipeline_set_layer_texture (pipeline, 0, offscreen_texture);
+
+  gles2_ctx = cogl_gles2_context_new (test_ctx, &error);
+  if (!gles2_ctx)
+    g_error ("Failed to create GLES2 context: %s\n", error->message);
+
+  gles2 = cogl_gles2_context_get_vtable (gles2_ctx);
+
+  /* Clear onscreen to 0xffff00 using GLES2 */
+
+  if (!cogl_push_gles2_context (test_ctx,
+                                gles2_ctx,
+                                test_fb,
+                                test_fb,
+                                &error))
+    {
+      g_error ("Failed to push gles2 context: %s\n", error->message);
+    }
+
+  gles2->glClearColor (1, 1, 0, 1);
+  gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+  cogl_pop_gles2_context (test_ctx);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0xffff00ff);
+
+  /* Clear offscreen to 0xff0000 using GLES2 and then copy the result
+   * onscreen.
+   *
+   * If we fail to bind the new context here then we'd probably end up
+   * clearing onscreen to 0xff0000 and copying 0xffff00 to onscreen
+   * instead.
+   */
+
+  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);
+    }
+
+  gles2->glClearColor (1, 0, 0, 1);
+  gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+  cogl_pop_gles2_context (test_ctx);
+
+  cogl_framebuffer_draw_rectangle (test_fb,
+                                   pipeline,
+                                   -1, 1, 1, -1);
+  /* NB: Cogl doesn't automatically support mid-scene modifications
+   * of textures and so we explicitly flush the drawn rectangle to the
+   * framebuffer now otherwise it may be batched until after the
+   * offscreen texture has been modified again. */
+  cogl_flush ();
+
+  /* Clear the offscreen framebuffer to blue using GLES2 before
+   * reading back from the onscreen framebuffer in case we mistakenly
+   * read from the offscreen framebuffer and get a false positive
+   */
+  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);
+    }
+
+  gles2->glClearColor (0, 0, 1, 1);
+  gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+  cogl_pop_gles2_context (test_ctx);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0xff0000ff);
+
+  /* Now copy the offscreen blue clear to the onscreen framebufer and
+   * check that too */
+  cogl_framebuffer_draw_rectangle (test_fb,
+                                   pipeline,
+                                   -1, 1, 1, -1);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0x0000ffff);
+
+  if (!cogl_push_gles2_context (test_ctx,
+                                gles2_ctx,
+                                test_fb,
+                                test_fb,
+                                &error))
+    {
+      g_error ("Failed to push gles2 context: %s\n", error->message);
+    }
+
+  gles2->glClearColor (1, 0, 1, 1);
+  gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+  cogl_pop_gles2_context (test_ctx);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0xff00ffff);
+
+
+  cogl_object_unref (gles2_ctx);
+
+  cogl_object_unref (pipeline);
+}
+
+static void
+create_gles2_context (CoglTexture **offscreen_texture,
+                      CoglOffscreen **offscreen,
+                      CoglPipeline **pipeline,
+                      CoglGLES2Context **gles2_ctx,
+                      const CoglGLES2Vtable **gles2)
+{
+  GError *error = NULL;
+
+  *offscreen_texture = COGL_TEXTURE (
+    cogl_texture_2d_new_with_size (test_ctx,
+                                   cogl_framebuffer_get_width (test_fb),
+                                   cogl_framebuffer_get_height (test_fb),
+                                   COGL_PIXEL_FORMAT_ANY,
+                                   NULL));
+  *offscreen = cogl_offscreen_new_to_texture (*offscreen_texture);
+
+  *pipeline = cogl_pipeline_new (test_ctx);
+  cogl_pipeline_set_layer_texture (*pipeline, 0, *offscreen_texture);
+
+  *gles2_ctx = cogl_gles2_context_new (test_ctx, NULL);
+  if (!*gles2_ctx)
+    g_error ("Failed to create GLES2 context: %s\n", error->message);
+
+  *gles2 = cogl_gles2_context_get_vtable (*gles2_ctx);
+}
+
+static void
+test_push_pop_multi_context (void)
+{
+  CoglTexture *offscreen_texture0;
+  CoglOffscreen *offscreen0;
+  CoglPipeline *pipeline0;
+  CoglGLES2Context *gles2_ctx0;
+  const CoglGLES2Vtable *gles20;
+  CoglTexture *offscreen_texture1;
+  CoglOffscreen *offscreen1;
+  CoglPipeline *pipeline1;
+  CoglGLES2Context *gles2_ctx1;
+  const CoglGLES2Vtable *gles21;
+  GError *error = NULL;
+
+  create_gles2_context (&offscreen_texture0,
+                        &offscreen0,
+                        &pipeline0,
+                        &gles2_ctx0,
+                        &gles20);
+
+  create_gles2_context (&offscreen_texture1,
+                        &offscreen1,
+                        &pipeline1,
+                        &gles2_ctx1,
+                        &gles21);
+
+  cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1);
+
+  if (!cogl_push_gles2_context (test_ctx,
+                                gles2_ctx0,
+                                COGL_FRAMEBUFFER (offscreen0),
+                                COGL_FRAMEBUFFER (offscreen0),
+                                &error))
+    {
+      g_error ("Failed to push gles2 context 0: %s\n", error->message);
+    }
+
+  gles20->glClearColor (1, 0, 0, 1);
+  gles20->glClear (GL_COLOR_BUFFER_BIT);
+
+  if (!cogl_push_gles2_context (test_ctx,
+                                gles2_ctx1,
+                                COGL_FRAMEBUFFER (offscreen1),
+                                COGL_FRAMEBUFFER (offscreen1),
+                                &error))
+    {
+      g_error ("Failed to push gles2 context 1: %s\n", error->message);
+    }
+
+  gles21->glClearColor (0, 1, 0, 1);
+  gles21->glClear (GL_COLOR_BUFFER_BIT);
+
+  cogl_pop_gles2_context (test_ctx);
+  cogl_pop_gles2_context (test_ctx);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0xffffffff);
+
+  cogl_framebuffer_draw_rectangle (test_fb,
+                                   pipeline0,
+                                   -1, 1, 1, -1);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0xff0000ff);
+
+  cogl_framebuffer_draw_rectangle (test_fb,
+                                   pipeline1,
+                                   -1, 1, 1, -1);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0x00ff00ff);
+}
+
+static GLuint
+create_gles2_framebuffer (const CoglGLES2Vtable *gles2,
+                          int width,
+                          int height)
+{
+  GLuint texture_handle;
+  GLuint fbo_handle;
+  GLenum status;
+
+  gles2->glGenTextures (1, &texture_handle);
+  gles2->glGenFramebuffers (1, &fbo_handle);
+
+  gles2->glBindTexture (GL_TEXTURE_2D, texture_handle);
+  gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gles2->glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
+                       GL_UNSIGNED_BYTE, NULL);
+  gles2->glBindTexture (GL_TEXTURE_2D, 0);
+
+  gles2->glBindFramebuffer (GL_FRAMEBUFFER, fbo_handle);
+  gles2->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                 GL_TEXTURE_2D, texture_handle, 0);
+
+  status = gles2->glCheckFramebufferStatus (GL_FRAMEBUFFER);
+  printf ("status for gles2 framebuffer = 0x%x %s\n",
+          status, status == GL_FRAMEBUFFER_COMPLETE ? "(complete)" : "(?)");
+
+  gles2->glBindFramebuffer (GL_FRAMEBUFFER, 0);
+
+  return fbo_handle;
+}
+
+static void
+test_gles2_read_pixels (void)
+{
+  CoglTexture *offscreen_texture;
+  CoglOffscreen *offscreen;
+  CoglPipeline *pipeline;
+  CoglGLES2Context *gles2_ctx;
+  const CoglGLES2Vtable *gles2;
+  GError *error = NULL;
+  GLubyte pixel[3];
+  GLuint fbo_handle;
+
+  create_gles2_context (&offscreen_texture,
+                        &offscreen,
+                        &pipeline,
+                        &gles2_ctx,
+                        &gles2);
+
+  cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1);
+
+  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);
+    }
+
+  gles2->glClearColor (1, 0, 0, 1);
+  gles2->glClear (GL_COLOR_BUFFER_BIT);
+  gles2->glReadPixels (0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pixel);
+
+  g_assert (pixel[0] == 0xff);
+  g_assert (pixel[1] == 0);
+  g_assert (pixel[2] == 0);
+
+  fbo_handle = create_gles2_framebuffer (gles2, 256, 256);
+
+  gles2->glBindFramebuffer (GL_FRAMEBUFFER, fbo_handle);
+
+  gles2->glClearColor (0, 1, 0, 1);
+  gles2->glClear (GL_COLOR_BUFFER_BIT);
+  gles2->glReadPixels (0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pixel);
+
+  g_assert (pixel[0] == 0);
+  g_assert (pixel[1] == 0xff);
+  g_assert (pixel[2] == 0);
+
+  gles2->glBindFramebuffer (GL_FRAMEBUFFER, 0);
+
+  gles2->glClearColor (0, 1, 1, 1);
+  gles2->glClear (GL_COLOR_BUFFER_BIT);
+  gles2->glReadPixels (0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pixel);
+
+  g_assert (pixel[0] == 0);
+  g_assert (pixel[1] == 0xff);
+  g_assert (pixel[2] == 0xff);
+
+  cogl_pop_gles2_context (test_ctx);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0xffffffff);
+
+  /* Bind different read and write buffers */
+  if (!cogl_push_gles2_context (test_ctx,
+                                gles2_ctx,
+                                COGL_FRAMEBUFFER (offscreen),
+                                test_fb,
+                                &error))
+    {
+      g_error ("Failed to push gles2 context: %s\n", error->message);
+    }
+
+  gles2->glReadPixels (0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pixel);
+
+  g_assert (pixel[0] == 0);
+  g_assert (pixel[1] == 0xff);
+  g_assert (pixel[2] == 0xff);
+
+  cogl_pop_gles2_context (test_ctx);
+
+  test_utils_check_pixel (test_fb, 0, 0, 0xffffffff);
+
+  /* Bind different read and write buffers (the other way around from
+   * before so when we test with COGL_TEST_ONSCREEN=1 we will read
+   * from an onscreen framebuffer) */
+  if (!cogl_push_gles2_context (test_ctx,
+                                gles2_ctx,
+                                test_fb,
+                                COGL_FRAMEBUFFER (offscreen),
+                                &error))
+    {
+      g_error ("Failed to push gles2 context: %s\n", error->message);
+    }
+
+  gles2->glReadPixels (0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pixel);
+
+  g_assert (pixel[0] == 0xff);
+  g_assert (pixel[1] == 0xff);
+  g_assert (pixel[2] == 0xff);
+
+  cogl_pop_gles2_context (test_ctx);
+}
+
+void
+test_gles2_context (void)
+{
+  test_push_pop_single_context ();
+  test_push_pop_multi_context ();
+  test_gles2_read_pixels ();
+
+  if (cogl_test_verbose ())
+    g_print ("OK\n");
+}
-- 
1.7.7.6



More information about the Cogl mailing list