fbo: Test using glBlitFramebuffer to convert between formats

Submitted by Neil Roberts on July 1, 2014, 3:06 p.m.

Details

Message ID 1404227168-11808-1-git-send-email-neil@linux.intel.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Neil Roberts July 1, 2014, 3:06 p.m.
Adds a test which creates renderbuffers with different internal
formats and tries to blit between them. The formats include RGB, RGBA,
depth and stencil buffers. The pixels of the buffers are set to four
known values before blitting using a scissored clear. The destination
buffer is then probed for the expected values.
---
 tests/all.py                 |   1 +
 tests/fbo/CMakeLists.gl.txt  |   1 +
 tests/fbo/fbo-blit-convert.c | 307 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 309 insertions(+)
 create mode 100644 tests/fbo/fbo-blit-convert.c

Patch hide | download patch | download mbox

diff --git a/tests/all.py b/tests/all.py
index 17d5d9b..bc3ca4e 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -1592,6 +1592,7 @@  for format in ('rgba', 'depth', 'stencil'):
         arb_framebuffer_object[test_name] = concurrent_test(test_name)
 add_concurrent_test(arb_framebuffer_object, 'fbo-alpha')
 add_plain_test(arb_framebuffer_object, 'fbo-blit-stretch')
+add_concurrent_test(arb_framebuffer_object, 'fbo-blit-convert')
 add_concurrent_test(arb_framebuffer_object, 'fbo-blit-scaled-linear')
 add_concurrent_test(arb_framebuffer_object, 'fbo-attachments-blit-scaled-linear')
 add_concurrent_test(arb_framebuffer_object, 'fbo-deriv')
diff --git a/tests/fbo/CMakeLists.gl.txt b/tests/fbo/CMakeLists.gl.txt
index 248519a..15de6d2 100644
--- a/tests/fbo/CMakeLists.gl.txt
+++ b/tests/fbo/CMakeLists.gl.txt
@@ -29,6 +29,7 @@  piglit_add_executable (fbo-bind-renderbuffer fbo-bind-renderbuffer.c)
 piglit_add_executable (fbo-blit fbo-blit.c)
 piglit_add_executable (fbo-blit-d24s8 fbo-blit-d24s8.c)
 piglit_add_executable (fbo-blit-stretch fbo-blit-stretch.cpp)
+piglit_add_executable (fbo-blit-convert fbo-blit-convert.c)
 piglit_add_executable (fbo-blending-formats fbo-blending-formats.c)
 piglit_add_executable (fbo-colormask-formats fbo-colormask-formats.c)
 piglit_add_executable (fbo-copypix fbo-copypix.c)
diff --git a/tests/fbo/fbo-blit-convert.c b/tests/fbo/fbo-blit-convert.c
new file mode 100644
index 0000000..5ebea17
--- /dev/null
+++ b/tests/fbo/fbo-blit-convert.c
@@ -0,0 +1,307 @@ 
+/*
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ */
+
+/** @file fbo-blit-convert.c
+ *
+ * Test using glBlitFramebuffer to blit between buffers that have
+ * different internal formats. The buffers are set up as renderbuffers
+ * and then rendered to with 4 known values using four scissored
+ * glClears. The values include RGBA, depth and stencil values. The
+ * cleared values are then blitted into the destination buffer. The
+ * destination is then probed for the expected values.
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 14;
+
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+struct format_test {
+	GLenum src_format, dst_format;
+	GLenum buffer_bit;
+	int n_components;
+	GLfloat expected_values[4][4];
+	const char *extension;
+};
+
+struct clear_value {
+	GLfloat rgba[4];
+	GLfloat depth;
+	GLint stencil;
+};
+
+static struct format_test
+tests[] = {
+	{ GL_RGB, GL_RGBA, GL_COLOR_BUFFER_BIT, 4,
+	  { { 0.0f, 0.33f, 0.66f, 1.0f },
+	    { 1.0f, 0.66f, 0.33f, 1.0f },
+	    { 1.0f, 1.0f, 1.0f, 1.0f },
+	    { 0.0f, 0.0f, 0.0f, 1.0f } } },
+	{ GL_RGBA, GL_RGB, GL_COLOR_BUFFER_BIT, 4,
+	  { { 0.0f, 0.33f, 0.66f, 1.0f },
+	    { 1.0f, 0.66f, 0.33f, 1.0f },
+	    { 1.0f, 1.0f, 1.0f, 1.0f },
+	    { 0.0f, 0.0f, 0.0f, 1.0f } } },
+	{ GL_RGBA, GL_RGB10_A2, GL_COLOR_BUFFER_BIT, 4,
+	  { { 0.0f, 0.33f, 0.66f, 1.0f },
+	    { 1.0f, 0.66f, 0.33f, 0.0f },
+	    { 1.0f, 1.0f, 1.0f, 1.0f },
+	    { 0.0f, 0.0f, 0.0f, 0.0f } } },
+	{ GL_RGB10_A2, GL_RGBA, GL_COLOR_BUFFER_BIT, 4,
+	  { { 0.0f, 0.33f, 0.66f, 1.0f },
+	    { 1.0f, 0.66f, 0.33f, 0.0f },
+	    { 1.0f, 1.0f, 1.0f, 1.0f },
+	    { 0.0f, 0.0f, 0.0f, 0.0f } } },
+	{ GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_BUFFER_BIT, 1,
+	  { { 0.0f },
+	    { 0.25f },
+	    { 0.75f },
+	    { 1.0f } } },
+	{ GL_STENCIL_INDEX4, GL_STENCIL_INDEX8, GL_STENCIL_BUFFER_BIT, 1,
+	  { { 0.0f },
+	    { 1.0f },
+	    { 2.0f },
+	    { 3.0f } } },
+};
+
+/* Four values used for the four pixels of the source renderbuffer */
+static const struct clear_value
+clear_values[4] = {
+	 { { 0.0f, 0.33f, 0.66f, 1.0f }, 0.0f, 0 },
+	 { { 1.0f, 0.66f, 0.33f, 0.0f }, 0.25f, 1 },
+	 { { 1.0f, 1.0f, 1.0f, 1.0f }, 0.75f, 2 },
+	 { { 0.0f, 0.0f, 0.0f, 0.0f }, 1.0f, 3 }
+};
+
+/* Dummy value to clear the destination buffer to before blitting */
+static const struct clear_value
+initial_clear_value;
+
+static void
+do_clear(const struct clear_value *value)
+{
+	glClearColor(value->rgba[0],
+		     value->rgba[1],
+		     value->rgba[2],
+		     value->rgba[3]);
+	glClearDepth(value->depth);
+	glClearStencil(value->stencil);
+	glClear(GL_COLOR_BUFFER_BIT |
+		GL_DEPTH_BUFFER_BIT |
+		GL_STENCIL_BUFFER_BIT);
+}
+
+static bool
+create_fb(GLuint *fb, GLuint *rb, GLenum format, GLenum attachment)
+{
+	glGenFramebuffers(1, fb);
+	glBindFramebuffer(GL_FRAMEBUFFER, *fb);
+
+	glGenRenderbuffers(1, rb);
+	glBindRenderbuffer(GL_RENDERBUFFER, *rb);
+	glRenderbufferStorage(GL_RENDERBUFFER, format, 4, 1);
+
+	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+				  attachment,
+				  GL_RENDERBUFFER,
+				  *rb);
+
+	glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
+	    GL_FRAMEBUFFER_COMPLETE) {
+		glBindFramebuffer(GL_FRAMEBUFFER, 0);
+		glDeleteRenderbuffers(1, rb);
+		glDeleteFramebuffers(1, fb);
+		return false;
+	}
+
+	do_clear(&initial_clear_value);
+
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+	return true;
+}
+
+static void
+dump_difference(const struct format_test *test,
+		int pixel_num,
+		const GLfloat *actual_values)
+{
+	int i;
+
+	printf("%s -> %s, pixel %i\n"
+	       " Expected:",
+	       piglit_get_gl_enum_name(test->src_format),
+	       piglit_get_gl_enum_name(test->dst_format),
+	       pixel_num);
+	for (i = 0; i < test->n_components; i++)
+		printf(" %f", test->expected_values[pixel_num][i]);
+	printf("\n"
+	       " Observed:");
+	for (i = 0; i < test->n_components; i++)
+		printf(" %f", actual_values[i]);
+	fputc('\n', stdout);
+}
+
+static bool
+verify(const struct format_test *test)
+{
+	GLfloat actual_values[4];
+	GLenum format = GL_RGBA;
+	int i, j;
+
+	switch (test->buffer_bit) {
+	case GL_COLOR_BUFFER_BIT:
+		format = GL_RGBA;
+		break;
+	case GL_DEPTH_BUFFER_BIT:
+		format = GL_DEPTH_COMPONENT;
+		break;
+	case GL_STENCIL_BUFFER_BIT:
+		format = GL_STENCIL_INDEX;
+		break;
+	}
+
+	for (i = 0; i < 4; i++) {
+		glReadPixels(i, 0, 1, 1, format, GL_FLOAT, actual_values);
+
+		for (j = 0; j < test->n_components; j++) {
+			if (fabs(test->expected_values[i][j] -
+				 actual_values[j]) >= piglit_tolerance[j]) {
+				dump_difference(test, i, actual_values);
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+static enum piglit_result
+run_test(const struct format_test *test)
+{
+	GLenum attachment = GL_COLOR_ATTACHMENT0;
+	enum piglit_result result = PIGLIT_PASS;
+	GLuint src_fb, dst_fb;
+	GLuint src_rb, dst_rb;
+	int i;
+
+	switch (test->buffer_bit) {
+	case GL_COLOR_BUFFER_BIT:
+		attachment = GL_COLOR_ATTACHMENT0;
+		break;
+	case GL_DEPTH_BUFFER_BIT:
+		attachment = GL_DEPTH_ATTACHMENT;
+		break;
+	case GL_STENCIL_BUFFER_BIT:
+		attachment = GL_STENCIL_ATTACHMENT;
+		break;
+	}
+
+	if (!create_fb(&src_fb, &src_rb, test->src_format, attachment)) {
+		printf("Failed to create framebuffer for %s format. "
+		       "Skipping test for %s->%s\n",
+		       piglit_get_gl_enum_name(test->src_format),
+		       piglit_get_gl_enum_name(test->src_format),
+		       piglit_get_gl_enum_name(test->dst_format));
+		result = PIGLIT_SKIP;
+		goto out;
+	}
+	if (!create_fb(&dst_fb, &dst_rb, test->dst_format, attachment)) {
+		printf("Failed to create framebuffer for %s format. "
+		       "Skipping test for %s->%s\n",
+		       piglit_get_gl_enum_name(test->dst_format),
+		       piglit_get_gl_enum_name(test->src_format),
+		       piglit_get_gl_enum_name(test->dst_format));
+		result = PIGLIT_SKIP;
+		goto out_src;
+	}
+
+	/* Setup the source buffer with the four test values */
+	glBindFramebuffer(GL_FRAMEBUFFER, src_fb);
+	glEnable(GL_SCISSOR_TEST);
+	for (i = 0; i < 4; i++) {
+		glScissor(i, 0, 1, 1);
+		do_clear(clear_values + i);
+	}
+	glDisable(GL_SCISSOR_TEST);
+
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, src_fb);
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_fb);
+
+	glBlitFramebuffer(0, 0, 4, 1, /* src x1/y1/x2/y2 */
+			  0, 0, 4, 1, /* dst x1/y1/x2/y2 */
+			  test->buffer_bit,
+			  GL_NEAREST);
+
+	glBindFramebuffer(GL_FRAMEBUFFER, dst_fb);
+
+	if (!verify(test))
+		result = PIGLIT_FAIL;
+
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+	glDeleteFramebuffers(1, &dst_fb);
+ out_src:
+	glDeleteFramebuffers(1, &src_fb);
+ out:
+	return result;
+}
+
+static bool
+run_all_tests(void)
+{
+	bool pass = true;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++)
+		if (run_test(tests + i) == PIGLIT_FAIL)
+			pass = false;
+
+	return pass;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	bool pass;
+
+	piglit_require_extension("GL_ARB_framebuffer_object");
+
+	pass = run_all_tests();
+
+	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
+}
+
+enum piglit_result
+piglit_display(void)
+{
+	/* unused */
+	return PIGLIT_FAIL;
+}

Comments

On Tuesday, July 01, 2014 04:06:08 PM Neil Roberts wrote:
> Adds a test which creates renderbuffers with different internal
> formats and tries to blit between them. The formats include RGB, RGBA,
> depth and stencil buffers. The pixels of the buffers are set to four
> known values before blitting using a scissored clear. The destination
> buffer is then probed for the expected values.
> ---
>  tests/all.py                 |   1 +
>  tests/fbo/CMakeLists.gl.txt  |   1 +
>  tests/fbo/fbo-blit-convert.c | 307 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 309 insertions(+)
>  create mode 100644 tests/fbo/fbo-blit-convert.c

Looks reasonable to me, and it's definitely nice to have more testing in this area.  There are probably some additional things we could check...particularly, any formats where we fall back to a generic RGBA format in the driver.

Comparing _mesa_choose_tex_format with brw_surface_format.c's list of supported/renderable formats would find those cases.  I think there are some SNORM ones, for example.  If you feel like it :)  If not, that's fine.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
(though my review is pretty light, so it's perhaps more of an Acked-by)

> diff --git a/tests/all.py b/tests/all.py
> index 17d5d9b..bc3ca4e 100644
> --- a/tests/all.py
> +++ b/tests/all.py
> @@ -1592,6 +1592,7 @@ for format in ('rgba', 'depth', 'stencil'):
>          arb_framebuffer_object[test_name] = concurrent_test(test_name)
>  add_concurrent_test(arb_framebuffer_object, 'fbo-alpha')
>  add_plain_test(arb_framebuffer_object, 'fbo-blit-stretch')
> +add_concurrent_test(arb_framebuffer_object, 'fbo-blit-convert')
>  add_concurrent_test(arb_framebuffer_object, 'fbo-blit-scaled-linear')
>  add_concurrent_test(arb_framebuffer_object, 'fbo-attachments-blit-scaled-linear')
>  add_concurrent_test(arb_framebuffer_object, 'fbo-deriv')
> diff --git a/tests/fbo/CMakeLists.gl.txt b/tests/fbo/CMakeLists.gl.txt
> index 248519a..15de6d2 100644
> --- a/tests/fbo/CMakeLists.gl.txt
> +++ b/tests/fbo/CMakeLists.gl.txt
> @@ -29,6 +29,7 @@ piglit_add_executable (fbo-bind-renderbuffer fbo-bind-renderbuffer.c)
>  piglit_add_executable (fbo-blit fbo-blit.c)
>  piglit_add_executable (fbo-blit-d24s8 fbo-blit-d24s8.c)
>  piglit_add_executable (fbo-blit-stretch fbo-blit-stretch.cpp)
> +piglit_add_executable (fbo-blit-convert fbo-blit-convert.c)
>  piglit_add_executable (fbo-blending-formats fbo-blending-formats.c)
>  piglit_add_executable (fbo-colormask-formats fbo-colormask-formats.c)
>  piglit_add_executable (fbo-copypix fbo-copypix.c)
> diff --git a/tests/fbo/fbo-blit-convert.c b/tests/fbo/fbo-blit-convert.c
> new file mode 100644
> index 0000000..5ebea17
> --- /dev/null
> +++ b/tests/fbo/fbo-blit-convert.c
> @@ -0,0 +1,307 @@
> +/*
> + * Copyright (c) 2014 Intel Corporation
> + *
> + * 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 (including the next
> + * paragraph) 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.
> + */
> +
> +/** @file fbo-blit-convert.c
> + *
> + * Test using glBlitFramebuffer to blit between buffers that have
> + * different internal formats. The buffers are set up as renderbuffers
> + * and then rendered to with 4 known values using four scissored
> + * glClears. The values include RGBA, depth and stencil values. The
> + * cleared values are then blitted into the destination buffer. The
> + * destination is then probed for the expected values.
> + */
> +
> +#include "piglit-util-gl-common.h"
> +
> +PIGLIT_GL_TEST_CONFIG_BEGIN
> +
> +	config.supports_gl_compat_version = 14;
> +
> +	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
> +
> +PIGLIT_GL_TEST_CONFIG_END
> +
> +struct format_test {
> +	GLenum src_format, dst_format;
> +	GLenum buffer_bit;
> +	int n_components;
> +	GLfloat expected_values[4][4];
> +	const char *extension;
> +};
> +
> +struct clear_value {
> +	GLfloat rgba[4];
> +	GLfloat depth;
> +	GLint stencil;
> +};
> +
> +static struct format_test
> +tests[] = {
> +	{ GL_RGB, GL_RGBA, GL_COLOR_BUFFER_BIT, 4,
> +	  { { 0.0f, 0.33f, 0.66f, 1.0f },
> +	    { 1.0f, 0.66f, 0.33f, 1.0f },
> +	    { 1.0f, 1.0f, 1.0f, 1.0f },
> +	    { 0.0f, 0.0f, 0.0f, 1.0f } } },
> +	{ GL_RGBA, GL_RGB, GL_COLOR_BUFFER_BIT, 4,
> +	  { { 0.0f, 0.33f, 0.66f, 1.0f },
> +	    { 1.0f, 0.66f, 0.33f, 1.0f },
> +	    { 1.0f, 1.0f, 1.0f, 1.0f },
> +	    { 0.0f, 0.0f, 0.0f, 1.0f } } },
> +	{ GL_RGBA, GL_RGB10_A2, GL_COLOR_BUFFER_BIT, 4,
> +	  { { 0.0f, 0.33f, 0.66f, 1.0f },
> +	    { 1.0f, 0.66f, 0.33f, 0.0f },
> +	    { 1.0f, 1.0f, 1.0f, 1.0f },
> +	    { 0.0f, 0.0f, 0.0f, 0.0f } } },
> +	{ GL_RGB10_A2, GL_RGBA, GL_COLOR_BUFFER_BIT, 4,
> +	  { { 0.0f, 0.33f, 0.66f, 1.0f },
> +	    { 1.0f, 0.66f, 0.33f, 0.0f },
> +	    { 1.0f, 1.0f, 1.0f, 1.0f },
> +	    { 0.0f, 0.0f, 0.0f, 0.0f } } },
> +	{ GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_BUFFER_BIT, 1,
> +	  { { 0.0f },
> +	    { 0.25f },
> +	    { 0.75f },
> +	    { 1.0f } } },
> +	{ GL_STENCIL_INDEX4, GL_STENCIL_INDEX8, GL_STENCIL_BUFFER_BIT, 1,
> +	  { { 0.0f },
> +	    { 1.0f },
> +	    { 2.0f },
> +	    { 3.0f } } },
> +};
> +
> +/* Four values used for the four pixels of the source renderbuffer */
> +static const struct clear_value
> +clear_values[4] = {
> +	 { { 0.0f, 0.33f, 0.66f, 1.0f }, 0.0f, 0 },
> +	 { { 1.0f, 0.66f, 0.33f, 0.0f }, 0.25f, 1 },
> +	 { { 1.0f, 1.0f, 1.0f, 1.0f }, 0.75f, 2 },
> +	 { { 0.0f, 0.0f, 0.0f, 0.0f }, 1.0f, 3 }
> +};
> +
> +/* Dummy value to clear the destination buffer to before blitting */
> +static const struct clear_value
> +initial_clear_value;
> +
> +static void
> +do_clear(const struct clear_value *value)
> +{
> +	glClearColor(value->rgba[0],
> +		     value->rgba[1],
> +		     value->rgba[2],
> +		     value->rgba[3]);
> +	glClearDepth(value->depth);
> +	glClearStencil(value->stencil);
> +	glClear(GL_COLOR_BUFFER_BIT |
> +		GL_DEPTH_BUFFER_BIT |
> +		GL_STENCIL_BUFFER_BIT);
> +}
> +
> +static bool
> +create_fb(GLuint *fb, GLuint *rb, GLenum format, GLenum attachment)
> +{
> +	glGenFramebuffers(1, fb);
> +	glBindFramebuffer(GL_FRAMEBUFFER, *fb);
> +
> +	glGenRenderbuffers(1, rb);
> +	glBindRenderbuffer(GL_RENDERBUFFER, *rb);
> +	glRenderbufferStorage(GL_RENDERBUFFER, format, 4, 1);
> +
> +	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
> +				  attachment,
> +				  GL_RENDERBUFFER,
> +				  *rb);
> +
> +	glBindRenderbuffer(GL_RENDERBUFFER, 0);
> +
> +	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
> +	    GL_FRAMEBUFFER_COMPLETE) {
> +		glBindFramebuffer(GL_FRAMEBUFFER, 0);
> +		glDeleteRenderbuffers(1, rb);
> +		glDeleteFramebuffers(1, fb);
> +		return false;
> +	}
> +
> +	do_clear(&initial_clear_value);
> +
> +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
> +
> +	return true;
> +}
> +
> +static void
> +dump_difference(const struct format_test *test,
> +		int pixel_num,
> +		const GLfloat *actual_values)
> +{
> +	int i;
> +
> +	printf("%s -> %s, pixel %i\n"
> +	       " Expected:",
> +	       piglit_get_gl_enum_name(test->src_format),
> +	       piglit_get_gl_enum_name(test->dst_format),
> +	       pixel_num);
> +	for (i = 0; i < test->n_components; i++)
> +		printf(" %f", test->expected_values[pixel_num][i]);
> +	printf("\n"
> +	       " Observed:");
> +	for (i = 0; i < test->n_components; i++)
> +		printf(" %f", actual_values[i]);
> +	fputc('\n', stdout);
> +}
> +
> +static bool
> +verify(const struct format_test *test)
> +{
> +	GLfloat actual_values[4];
> +	GLenum format = GL_RGBA;
> +	int i, j;
> +
> +	switch (test->buffer_bit) {
> +	case GL_COLOR_BUFFER_BIT:
> +		format = GL_RGBA;
> +		break;
> +	case GL_DEPTH_BUFFER_BIT:
> +		format = GL_DEPTH_COMPONENT;
> +		break;
> +	case GL_STENCIL_BUFFER_BIT:
> +		format = GL_STENCIL_INDEX;
> +		break;
> +	}
> +
> +	for (i = 0; i < 4; i++) {
> +		glReadPixels(i, 0, 1, 1, format, GL_FLOAT, actual_values);
> +
> +		for (j = 0; j < test->n_components; j++) {
> +			if (fabs(test->expected_values[i][j] -
> +				 actual_values[j]) >= piglit_tolerance[j]) {
> +				dump_difference(test, i, actual_values);
> +				return false;
> +			}
> +		}
> +	}
> +
> +	return true;
> +}
> +
> +static enum piglit_result
> +run_test(const struct format_test *test)
> +{
> +	GLenum attachment = GL_COLOR_ATTACHMENT0;
> +	enum piglit_result result = PIGLIT_PASS;
> +	GLuint src_fb, dst_fb;
> +	GLuint src_rb, dst_rb;
> +	int i;
> +
> +	switch (test->buffer_bit) {
> +	case GL_COLOR_BUFFER_BIT:
> +		attachment = GL_COLOR_ATTACHMENT0;
> +		break;
> +	case GL_DEPTH_BUFFER_BIT:
> +		attachment = GL_DEPTH_ATTACHMENT;
> +		break;
> +	case GL_STENCIL_BUFFER_BIT:
> +		attachment = GL_STENCIL_ATTACHMENT;
> +		break;
> +	}
> +
> +	if (!create_fb(&src_fb, &src_rb, test->src_format, attachment)) {
> +		printf("Failed to create framebuffer for %s format. "
> +		       "Skipping test for %s->%s\n",
> +		       piglit_get_gl_enum_name(test->src_format),
> +		       piglit_get_gl_enum_name(test->src_format),
> +		       piglit_get_gl_enum_name(test->dst_format));
> +		result = PIGLIT_SKIP;
> +		goto out;
> +	}
> +	if (!create_fb(&dst_fb, &dst_rb, test->dst_format, attachment)) {
> +		printf("Failed to create framebuffer for %s format. "
> +		       "Skipping test for %s->%s\n",
> +		       piglit_get_gl_enum_name(test->dst_format),
> +		       piglit_get_gl_enum_name(test->src_format),
> +		       piglit_get_gl_enum_name(test->dst_format));
> +		result = PIGLIT_SKIP;
> +		goto out_src;
> +	}
> +
> +	/* Setup the source buffer with the four test values */
> +	glBindFramebuffer(GL_FRAMEBUFFER, src_fb);
> +	glEnable(GL_SCISSOR_TEST);
> +	for (i = 0; i < 4; i++) {
> +		glScissor(i, 0, 1, 1);
> +		do_clear(clear_values + i);
> +	}
> +	glDisable(GL_SCISSOR_TEST);
> +
> +	glBindFramebuffer(GL_READ_FRAMEBUFFER, src_fb);
> +	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_fb);
> +
> +	glBlitFramebuffer(0, 0, 4, 1, /* src x1/y1/x2/y2 */
> +			  0, 0, 4, 1, /* dst x1/y1/x2/y2 */
> +			  test->buffer_bit,
> +			  GL_NEAREST);
> +
> +	glBindFramebuffer(GL_FRAMEBUFFER, dst_fb);
> +
> +	if (!verify(test))
> +		result = PIGLIT_FAIL;
> +
> +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
> +
> +	glDeleteFramebuffers(1, &dst_fb);
> + out_src:
> +	glDeleteFramebuffers(1, &src_fb);
> + out:
> +	return result;
> +}
> +
> +static bool
> +run_all_tests(void)
> +{
> +	bool pass = true;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(tests); i++)
> +		if (run_test(tests + i) == PIGLIT_FAIL)
> +			pass = false;
> +
> +	return pass;
> +}
> +
> +void
> +piglit_init(int argc, char **argv)
> +{
> +	bool pass;
> +
> +	piglit_require_extension("GL_ARB_framebuffer_object");
> +
> +	pass = run_all_tests();
> +
> +	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
> +}
> +
> +enum piglit_result
> +piglit_display(void)
> +{
> +	/* unused */
> +	return PIGLIT_FAIL;
> +}
>