pixelzoom: New test for glPixelZoom()/glDrawPixels() validation

Submitted by Daniel J Sebald on March 30, 2015, 5:16 a.m.

Details

Message ID 5518DC23.60409@ieee.org
State New
Headers show

Not browsing as part of any series.

Commit Message

Daniel J Sebald March 30, 2015, 5:16 a.m.
Hello Piglit,

Attached is a proposed test for glPixelZoom() that has a number of 
individual tests.  The test came about because of some vertical line 
artifacts appearing in the legacy swrast_dri.so driver on my system and 
apparently a couple others' systems I inquired with.

The tests consist of a gradient test to suss any problems with large 
input images spanning GL_MAX_TEXTURE_SIZE, a stringent endpoint value 
test to see if the driver is agreeing with the OpenGL formula 
definitions, and an alternating color residue test of successively 
smaller boxes to see if the scaling is being done correctly.

All tests are open for debate--point being that working out the 
correctness of the tests should in the long run make all drivers for 
various platforms more consistent.

For a good summary of the tests, browse through the PNG files showing 
the output image for each test for legacy, patched legacy, Gallium and 
simple-mod Gallium drivers here:

https://bugs.freedesktop.org/show_bug.cgi?id=89586

Regards,

Dan Sebald

Patch hide | download patch | download mbox

From 96bcf7961ac7248e15eb5a54909931c3a6058a34 Mon Sep 17 00:00:00 2001
From: Daniel J Sebald <daniel.sebald@ieee.org>
Date: Sun, 29 Mar 2015 22:47:11 -0500
Subject: [PATCH] pixelzoom: New test for glPixelZoom()/glDrawPixels()
 validation

This test brings to light inconsistencies in both legacy and Gallium
swrast drivers when fractionally zooming large images.
---
 tests/spec/gl-1.0/CMakeLists.gl.txt |    1 +
 tests/spec/gl-1.0/pixelzoom.c       |  516 +++++++++++++++++++++++++++++++++++
 2 files changed, 517 insertions(+), 0 deletions(-)
 create mode 100644 tests/spec/gl-1.0/pixelzoom.c

diff --git a/tests/spec/gl-1.0/CMakeLists.gl.txt b/tests/spec/gl-1.0/CMakeLists.gl.txt
index e2e6642..e619a6a 100644
--- a/tests/spec/gl-1.0/CMakeLists.gl.txt
+++ b/tests/spec/gl-1.0/CMakeLists.gl.txt
@@ -25,5 +25,6 @@  piglit_add_executable (gl-1.0-ortho-pos orthpos.c)
 piglit_add_executable (gl-1.0-fpexceptions fpexceptions.c)
 piglit_add_executable (gl-1.0-readpixsanity readpix.c)
 piglit_add_executable (gl-1.0-logicop logicop.c)
+piglit_add_executable (gl-1.0-pixelzoom pixelzoom.c)
 
 # vim: ft=cmake:
diff --git a/tests/spec/gl-1.0/pixelzoom.c b/tests/spec/gl-1.0/pixelzoom.c
new file mode 100644
index 0000000..11a213d
--- /dev/null
+++ b/tests/spec/gl-1.0/pixelzoom.c
@@ -0,0 +1,516 @@ 
+/*
+ * Copyright (C) 2015 Dan Sebald
+ *
+ * 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 pixelzoom.c
+ *
+ * Test that a reasonably valid zoomed image is created, especially
+ * in the case that the dimension of the input image exceeds that
+ * of the texture maximum size, i.e., GL_MAX_TEXTURE_SIZE.  Do the
+ * following for positive xfactor/yfactor and negative xfactor/yfactor:
+ *
+ * 1. Create a ramp gradient and fractionally zoom to display size.
+ *    Check that frame buffer is monotonically increasing.
+ * 2. Choose the zoom factor xfactor/yfactor such that the last pixel
+ *    of the frame buffer is 1.0.  Check whether that is the case.
+ * 3. With an input image all of the same intensity/color, display
+ *    alternating image intensities (0.25 and 0.75) at successively
+ *    smaller zoom factors so that one pixel is left behind from each
+ *    drawing underneath the successor.  The result should be alternating
+ *    color lines.  Do this for both a magnification and a condensation.
+ */
+
+#include "piglit-util-gl.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+GLint prog, color, zflip;
+
+enum piglit_result
+piglit_display(void)
+{
+	bool pass_posmonx = true, pass_posedgex = true, pass_posoverunderrunx = true;
+	bool pass_negmonx = true, pass_negedgex = true, pass_negoverunderrunx = true;
+	bool pass_posmony = true, pass_posedgey = true, pass_posoverunderruny = true;
+	bool pass_negmony = true, pass_negedgey = true, pass_negoverunderruny = true;
+	bool pass_all = true;
+
+	GLint glmaxtexturesize;
+	int large_dim_size;
+	GLfloat *pixels;
+
+#define SMALL_DIM_SIZE 20
+	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glmaxtexturesize);
+	large_dim_size = 5 * glmaxtexturesize / 2;
+
+	pixels = (GLfloat *) malloc(sizeof(GLfloat) * large_dim_size * SMALL_DIM_SIZE * 4);
+
+	if (pixels) {
+
+		int i;
+		GLfloat background_color[4] = {0.0, 0.8, 0.0, 1.0};
+
+		/* Positive Monotonicity X Test:  Place a gradient in one direction into the
+		 * input image and the zoomed resultant image must be a gradient.
+		 */
+		glRasterPos2i(0, 0);
+		glPixelZoom(piglit_width, piglit_height);
+		glDrawPixels(1, 1, GL_RGBA, GL_FLOAT, background_color);
+		for (i = 0; i < SMALL_DIM_SIZE; i++) {
+			int j;
+			long int n = 4 * large_dim_size * i;
+			for (j = 0; j < large_dim_size; j++) {
+				GLfloat pval = j / (GLfloat) (large_dim_size - 1);
+				pixels[n++] = pval;
+				pixels[n++] = pval;
+				pixels[n++] = pval;
+				pixels[n++] = 1.0;
+			}
+		}
+		glRasterPos2i(0, 0);
+		glPixelZoom((piglit_width - 1) / (GLfloat) (large_dim_size - 1), (piglit_height - 1) / (GLfloat) (SMALL_DIM_SIZE - 1));
+		glDrawPixels(large_dim_size, SMALL_DIM_SIZE, GL_RGBA, GL_FLOAT, pixels);
+		for (i = 0; i < piglit_height; i++) {
+			int j;
+			GLfloat prev_pval = 0.0;
+			for (j = 0; j < piglit_width; j++) {
+				GLfloat pval[4];
+				glReadPixels(j, i, 1, 1, GL_RGBA, GL_FLOAT, pval);
+				if ((pval[0] + pval[1] + pval[2]) < prev_pval) {
+					pass_posmonx = false;
+					break;
+				}
+				prev_pval = (pval[0] + pval[1] + pval[2]);
+			}
+		}
+
+		/* Positive Edge Value X Test:  The positive zoom xfactor was chosen such
+		 * that the last pixel of the output image should equal 1.0.
+		 *
+		 * Given xr + n * xfactor <= pix_center < xr + (n+1) * xfactor,
+		 * and N is input image width, for pixel piglit_width-1 to be in
+		 * the box associated with 1.0 requires
+		 *
+		 *   0 + (N-1) * xfactor = pixel_width-1
+		 *
+		 * or
+		 *
+		 *   xfactor = (pixel_width - 1) / (N - 1)
+		 */
+		for (i = 0; i < piglit_height; i++) {
+			GLfloat pval[4];
+			glReadPixels(0, i, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != 0.0) {
+				pass_posedgex = false;
+				break;
+			}
+			glReadPixels(piglit_width - 1, i, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != 3.0) {
+				pass_posedgex = false;
+				break;
+			}
+		}
+
+		/* Negative Monotonicity X Test:  Use the same gradient input image as for
+		 * the positive monotonicity test.
+		 */
+		glRasterPos2i(0, 0);
+		glPixelZoom(piglit_width, piglit_height);
+		glDrawPixels(1, 1, GL_RGBA, GL_FLOAT, background_color);
+		glRasterPos2i(piglit_width, piglit_height);
+		glPixelZoom(-piglit_width / (GLfloat) large_dim_size, -piglit_height / (GLfloat) SMALL_DIM_SIZE);
+		glDrawPixels(large_dim_size, SMALL_DIM_SIZE, GL_RGBA, GL_FLOAT, pixels);
+		for (i = 0; i < piglit_height; i++) {
+			int j;
+			GLfloat prev_pval = 0.0;
+			for (j = piglit_width-1; j >= 0; j--) {
+				GLfloat pval[4];
+				glReadPixels(j, i, 1, 1, GL_RGBA, GL_FLOAT, pval);
+				if ((pval[0] + pval[1] + pval[2]) < prev_pval) {
+					pass_negmonx = false;
+					break;
+				}
+				prev_pval = (pval[0] + pval[1] + pval[2]);
+			}
+		}
+
+		/* Negative Edge Value X Test:  The negative zoom xfactor was chosen such
+		 * that the last pixel of the output image should equal 1.0.
+		 *
+		 * Given xr + (n+1) * xfactor <= pix_center < xr + n * xfactor,
+		 * and N is input image width, for pixel 0 to be in box associated
+		 * with 1.0 requires
+		 *
+		 *   pixel_width + ((N-1)+1) * xfactor = 0
+		 *
+		 * or
+		 *
+		 *   xfactor = -pixel_width / N
+		 */
+		for (i = 0; i < piglit_height; i++) {
+			GLfloat pval[4];
+			glReadPixels(0, i, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != 3.0) {
+				pass_negedgex = false;
+				break;
+			}
+#if 0
+			/* One might think this first "negative" pixel would be
+			 * 0.0, but there is no formula to establish this.  The
+			 * reason is really tied to the fact that the pixel at
+			 * (xr,yr) is not inclusive when xfactor and yfactor are
+			 * negative because its center falls on the right and top
+			 * edges of the [xr+xfactor,xr) x [yr+yfactor,yr) box.
+			 */
+			glReadPixels(piglit_width - 1, i, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != ##) {
+				pass_negedgex = false;
+				break;
+			}
+#endif
+		}
+
+#define PIXEL_TOLERANCE 0.01
+
+		/* Positive and Negative Over/Underrun X Test:  Scale a single-valued
+		 * block of pixels with multiple xfactor values to leave behind a
+         * single line effectively alternating lines of two intensities.  Do
+         * once with magnification, once with condensation.
+		 */
+		for (i = 0; i < 4; i++) {
+			GLfloat *pixels_1 = 0, *pixels_2 = 0;
+			GLint input_width, input_height;
+			bool *test_flag;
+			GLfloat x_sign;
+			glRasterPos2i(0, 0);
+			glPixelZoom(piglit_width, piglit_height);
+			glDrawPixels(1, 1, GL_RGBA, GL_FLOAT, background_color);
+			input_height = 1;
+			if (i == ((i >> 1) << 1))
+				input_width = 5;
+			else
+				input_width = 5 * piglit_height / 2;
+			if (i == 0 || i == 1) {
+				glRasterPos2i(0, 0);
+				test_flag = &pass_posoverunderrunx;
+				x_sign = 1.0;
+			}
+			else {
+				glRasterPos2i(piglit_width, 0);
+				test_flag = &pass_negoverunderrunx;
+				x_sign = -1.0;
+			}
+			pixels_1 = (GLfloat *) malloc(sizeof(GLfloat) * input_width * input_height * 4);
+			pixels_2 = (GLfloat *) malloc(sizeof(GLfloat) * input_width * input_height * 4);
+			if (pixels_1 && pixels_2) {
+				long int n = 0;
+				int j;
+				for (j = 0; j < input_width; j++) {
+					pixels_1[n] = 0.25;
+					pixels_2[n++] = 0.75;
+					pixels_1[n] = 0.25;
+					pixels_2[n++] = 0.75;
+					pixels_1[n] = 0.25;
+					pixels_2[n++] = 0.75;
+					pixels_1[n] = 1.0;
+					pixels_2[n++] = 0.75;
+				}
+				for (j = 0; j < piglit_width; j++) {
+					GLfloat *pixel_array;
+					if (j == ((j >> 1) << 1))
+						pixel_array = pixels_1;
+					else
+						pixel_array = pixels_2;
+					glPixelZoom(x_sign * (piglit_width - j) / (GLfloat) input_width, piglit_height / (GLfloat) input_height);
+					glDrawPixels(input_width, input_height, GL_RGBA, GL_FLOAT, pixel_array);
+				}
+				for (j = 0; j < piglit_width; j++) {
+					GLfloat pval[4];
+					glReadPixels((x_sign > 0) ? piglit_width - 1 - j : j, piglit_height/2, 1, 1, GL_RGBA, GL_FLOAT, pval);
+					if (j == ((j >> 1) << 1)) {
+						if (fabs((pval[0] + pval[1] + pval[2]) - 3 * 0.25) > PIXEL_TOLERANCE) {
+							*test_flag = false;
+							break;
+						}
+					}
+					else {
+						if (fabs((pval[0] + pval[1] + pval[2]) - 3 * 0.75) > PIXEL_TOLERANCE) {
+							*test_flag = false;
+							break;
+						}
+					}
+				}
+			}
+			if (pixels_1)
+				free(pixels_1);
+			if (pixels_2)
+				free(pixels_2);
+		}
+
+		/* Positive Monotonicity Y Test:  Place a gradient in one direction into the
+		 * input image and the zoomed resultant image must be a gradient.
+		 */
+		glRasterPos2i(0, 0);
+		glPixelZoom(piglit_width, piglit_height);
+		glDrawPixels(1, 1, GL_RGBA, GL_FLOAT, background_color);
+		for (i = 0; i < large_dim_size; i++) {
+			int j;
+			long int n = 4 * SMALL_DIM_SIZE * i;
+			GLfloat pval = i / (GLfloat) (large_dim_size - 1);
+			for (j = 0; j < SMALL_DIM_SIZE; j++) {
+				pixels[n++] = pval;
+				pixels[n++] = pval;
+				pixels[n++] = pval;
+				pixels[n++] = 1.0;
+			}
+		}
+		glRasterPos2i(0, 0);
+		glPixelZoom((piglit_width - 1) / (GLfloat) (SMALL_DIM_SIZE - 1), (piglit_height - 1) / (GLfloat) (large_dim_size - 1));
+		glDrawPixels(SMALL_DIM_SIZE, large_dim_size, GL_RGBA, GL_FLOAT, pixels);
+		for (i = 0; i < piglit_width; i++) {
+			int j;
+			GLfloat prev_pval = 0.0;
+			for (j = 0; j < piglit_height; j++) {
+				GLfloat pval[4];
+				glReadPixels(i, j, 1, 1, GL_RGBA, GL_FLOAT, pval);
+				if ((pval[0] + pval[1] + pval[2]) < prev_pval) {
+					pass_posmony = false;
+					break;
+				}
+				prev_pval = (pval[0] + pval[1] + pval[2]);
+			}
+		}
+
+		/* Positive Edge Value Y Test:  The positive zoom yfactor was chosen such
+		 * that the last pixel of the output image should equal 1.0.
+		 *
+		 * Given yr + m * yfactor <= pix_center < yr + (n+1) * yfactor,
+		 * and M is input image width, for pixel piglit_height-1 to be in
+		 * the box associated with 1.0 requires
+		 *
+		 *   0 + (M-1) * yfactor = pixel_height-1
+		 *
+		 * or
+		 *
+		 *   yfactor = (pixel_height - 1) / (M - 1)
+		 */
+		for (i = 0; i < piglit_width; i++) {
+			GLfloat pval[4];
+			glReadPixels(i, 0, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != 0.0) {
+				pass_posedgey = false;
+				break;
+			}
+			glReadPixels(i, piglit_height - 1, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != 3.0) {
+				pass_posedgey = false;
+				break;
+			}
+		}
+
+		/* Negative Monotonicity Y Test:  Use the same gradient input image as for
+		 * the positive monotonicity test.
+		 */
+		glRasterPos2i(0, 0);
+		glPixelZoom(piglit_width, piglit_height);
+		glDrawPixels(1, 1, GL_RGBA, GL_FLOAT, background_color);
+		glRasterPos2i(piglit_width, piglit_height);
+		glPixelZoom(-piglit_width / (GLfloat) SMALL_DIM_SIZE, -piglit_height / (GLfloat) large_dim_size);
+		glDrawPixels(SMALL_DIM_SIZE, large_dim_size, GL_RGBA, GL_FLOAT, pixels);
+		for (i = 0; i < piglit_width; i++) {
+			int j;
+			GLfloat prev_pval = 0.0;
+			for (j = piglit_height-1; j >= 0; j--) {
+				GLfloat pval[4];
+				glReadPixels(i, j, 1, 1, GL_RGBA, GL_FLOAT, pval);
+				if ((pval[0] + pval[1] + pval[2]) < prev_pval) {
+					pass_negmony = false;
+					break;
+				}
+				prev_pval = (pval[0] + pval[1] + pval[2]);
+			}
+		}
+
+		/* Negative Edge Value Y Test:  The positive zoom xfactor was chosen such
+		 * that the last pixel of the output image should equal 1.0.
+		 *
+		 * Given yr + (m+1) * yfactor <= pix_center < yr + m * yfactor,
+		 * and M is input image width, for pixel 0 to be in box associated
+		 * with 1.0 requires
+		 *
+		 *   pixel_height + ((M-1)+1) * yfactor = 0
+		 *
+		 * or
+		 *
+		 *   yfactor = -pixel_height / M
+		 */
+		for (i = 0; i < piglit_width; i++) {
+			GLfloat pval[4];
+			glReadPixels(i, 0, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != 3.0) {
+				pass_negedgey = false;
+				break;
+			}
+#if 0
+			glReadPixels(i, piglit_height - 1, 1, 1, GL_RGBA, GL_FLOAT, pval);
+			if ((pval[0] + pval[1] + pval[2]) != ##) {
+				pass_negedgex = false;
+				break;
+			}
+#endif
+		}
+
+		/* Positive and Negative Over/Underrun Y Test:  Scale a single-valued
+		 * block of pixels with multiple yfactor values to leave behind a
+         * single line effectively alternating lines of two intensities.  Do
+         * once with magnification, once with condensation.
+		 */
+		for (i = 0; i < 4; i++) {
+			GLfloat *pixels_1 = 0, *pixels_2 = 0;
+			GLint input_width, input_height;
+			bool *test_flag;
+			GLfloat y_sign;
+			glRasterPos2i(0, 0);
+			glPixelZoom(piglit_width, piglit_height);
+			glDrawPixels(1, 1, GL_RGBA, GL_FLOAT, background_color);
+			input_width = 1;
+			if (i == ((i >> 1) << 1))
+				input_height = 5;
+			else
+				input_height = 5 * piglit_height / 2;
+			if (i == 0 || i == 1) {
+				glRasterPos2i(0, 0);
+				test_flag = &pass_posoverunderruny;
+				y_sign = 1.0;
+			}
+			else {
+				glRasterPos2i(0, piglit_height);
+				test_flag = &pass_negoverunderruny;
+				y_sign = -1.0;
+			}
+			pixels_1 = (GLfloat *) malloc(sizeof(GLfloat) * input_width * input_height * 4);
+			pixels_2 = (GLfloat *) malloc(sizeof(GLfloat) * input_width * input_height * 4);
+			if (pixels_1 && pixels_2) {
+				long int n = 0;
+				int j;
+				for (j = 0; j < (input_width * input_height); j++) {
+					pixels_1[n] = 0.25;
+					pixels_2[n++] = 0.75;
+					pixels_1[n] = 0.25;
+					pixels_2[n++] = 0.75;
+					pixels_1[n] = 0.25;
+					pixels_2[n++] = 0.75;
+					pixels_1[n] = 1.0;
+					pixels_2[n++] = 0.75;
+				}
+				for (j = 0; j < piglit_height; j++) {
+					GLfloat *pixel_array;
+					if (j == ((j >> 1) << 1))
+						pixel_array = pixels_1;
+					else
+						pixel_array = pixels_2;
+					glPixelZoom(piglit_width / (GLfloat) input_width, y_sign * (piglit_height - j) / (GLfloat) input_height);
+					glDrawPixels(input_width, input_height, GL_RGBA, GL_FLOAT, pixel_array);
+				}
+				for (j = 0; j < piglit_height; j++) {
+					GLfloat pval[4];
+					glReadPixels(piglit_width/2, (y_sign > 0) ? piglit_height - 1 - j : j, 1, 1, GL_RGBA, GL_FLOAT, pval);
+					if (j == ((j >> 1) << 1)) {
+						if (fabs((pval[0] + pval[1] + pval[2]) - 3 * 0.25) > PIXEL_TOLERANCE) {
+							*test_flag = false;
+							break;
+						}
+					}
+					else {
+						if (fabs((pval[0] + pval[1] + pval[2]) - 3 * 0.75) > PIXEL_TOLERANCE) {
+							*test_flag = false;
+							break;
+						}
+					}
+				}
+			}
+			if (pixels_1)
+				free(pixels_1);
+			if (pixels_2)
+				free(pixels_2);
+		}
+
+		free(pixels);
+	}
+
+	piglit_report_subtest_result(pass_posmonx ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "positive monotonic x");
+	piglit_report_subtest_result(pass_posedgex ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "positive edge x");
+	piglit_report_subtest_result(pass_posoverunderrunx ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "positive over/underrun x");
+	piglit_report_subtest_result(pass_negmonx ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "negative monotonic x");
+	piglit_report_subtest_result(pass_negedgex ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "negative edge x");
+	piglit_report_subtest_result(pass_negoverunderrunx ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "negative over/underrun x");
+	piglit_report_subtest_result(pass_posmony ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "positive monotonic y");
+	piglit_report_subtest_result(pass_posedgey ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "positive edge y");
+	piglit_report_subtest_result(pass_posoverunderruny ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "positive over/underrun y");
+	piglit_report_subtest_result(pass_negmony ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "negative monotonic y");
+	piglit_report_subtest_result(pass_negedgey ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "negative edge y");
+	piglit_report_subtest_result(pass_negoverunderruny ? PIGLIT_PASS : PIGLIT_FAIL,
+				     "negative over/underrun y");
+
+	pass_all = pass_posmonx && pass_posedgex && pass_posoverunderrunx &&
+			   pass_negmonx && pass_negedgex && pass_negoverunderrunx &&
+			   pass_posmony && pass_posedgey && pass_posoverunderruny &&
+			   pass_negmony && pass_negedgey && pass_negoverunderruny;
+
+	piglit_report_subtest_result(pass_all ? PIGLIT_PASS : PIGLIT_FAIL, "END OF PIXELZOOM TESTS");
+
+	piglit_present_results();
+
+	return (pass_all ? PIGLIT_PASS : PIGLIT_FAIL);
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	prog = piglit_build_simple_program(
+			"#version 120\n"
+			"uniform float zflip;\n"
+			"void main() { gl_Position = gl_Vertex * vec4(1, 1, zflip, 1); }\n",
+
+			"#version 120\n"
+			"uniform vec4 color;\n"
+			"void main() { gl_FragColor = color; }\n");
+
+	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
+}
-- 
1.7.4.4