[Piglit] [PATCH 1/3] Make the functions in ext_framebuffer_multisample/common.cpp available globally

Anuj Phogat anuj.phogat at gmail.com
Fri Aug 9 14:56:51 PDT 2013


A lot of classes and functions in ext_framebuffer_multisample/common.cpp
can be utilized to develop new piglit test cases. This patch moves the
Fbo and test_pattern classes to a global location tests/util.
Functions from these classes will be utilized in my later patches for
tests in spec/arb_framebuffer_object.

Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
---
 tests/spec/ext_framebuffer_multisample/common.cpp | 1112 ---------------------
 tests/spec/ext_framebuffer_multisample/common.h   |  403 +-------
 tests/util/CMakeLists.gl.txt                      |    2 +
 tests/util/piglit-fbo.cpp                         |  204 ++++
 tests/util/piglit-fbo.h                           |  139 +++
 tests/util/piglit-test-pattern.cpp                |  967 ++++++++++++++++++
 tests/util/piglit-test-pattern.h                  |  322 ++++++
 7 files changed, 1636 insertions(+), 1513 deletions(-)
 create mode 100644 tests/util/piglit-fbo.cpp
 create mode 100644 tests/util/piglit-fbo.h
 create mode 100644 tests/util/piglit-test-pattern.cpp
 create mode 100644 tests/util/piglit-test-pattern.h

diff --git a/tests/spec/ext_framebuffer_multisample/common.cpp b/tests/spec/ext_framebuffer_multisample/common.cpp
index 65f98f7..1217f54 100644
--- a/tests/spec/ext_framebuffer_multisample/common.cpp
+++ b/tests/spec/ext_framebuffer_multisample/common.cpp
@@ -110,182 +110,6 @@
 
 #include "common.h"
 
-FboConfig::FboConfig(int num_samples, int width, int height)
-	: num_samples(num_samples),
-	  width(width),
-	  height(height),
-	  combine_depth_stencil(true),
-	  attach_texture(false),
-	  color_internalformat(GL_RGBA),
-	  depth_internalformat(GL_DEPTH_COMPONENT24),
-	  stencil_internalformat(GL_STENCIL_INDEX8)
-{
-}
-
-Fbo::Fbo()
-	: config(0, 0, 0), /* will be overwritten on first call to setup() */
-	  handle(0),
-	  color_tex(0),
-	  color_rb(0),
-	  depth_rb(0),
-	  stencil_rb(0),
-	  gl_objects_generated(false)
-{
-}
-
-void
-Fbo::generate_gl_objects(void)
-{
-	glGenFramebuffers(1, &handle);
-	glGenTextures(1, &color_tex);
-	glGenRenderbuffers(1, &color_rb);
-	glGenRenderbuffers(1, &depth_rb);
-	glGenRenderbuffers(1, &stencil_rb);
-	gl_objects_generated = true;
-}
-
-void
-Fbo::set_samples(int num_samples)
-{
-	FboConfig new_config = this->config;
-	new_config.num_samples = num_samples;
-	setup(new_config);
-}
-
-/**
- * Modify the state of the framebuffer object to reflect the state in
- * new_config.  if the resulting framebuffer is incomplete, terminate
- * the test.
- */
-void
-Fbo::setup(const FboConfig &new_config)
-{
-	if (!try_setup(new_config)) {
-		printf("Framebuffer not complete\n");
-		piglit_report_result(PIGLIT_SKIP);
-	}
-}
-
-
-/**
- * Modify the state of the framebuffer object to reflect the state in
- * config.  Return true if the resulting framebuffer is complete,
- * false otherwise.
- */
-bool
-Fbo::try_setup(const FboConfig &new_config)
-{
-	this->config = new_config;
-
-	if (!gl_objects_generated)
-		generate_gl_objects();
-
-	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, handle);
-
-	/* Color buffer */
-	if (config.color_internalformat != GL_NONE) {
-		if (!config.attach_texture) {
-			glBindRenderbuffer(GL_RENDERBUFFER, color_rb);
-			glRenderbufferStorageMultisample(GL_RENDERBUFFER,
-							 config.num_samples,
-							 config.color_internalformat,
-							 config.width,
-							 config.height);
-			glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
-						  GL_COLOR_ATTACHMENT0,
-						  GL_RENDERBUFFER, color_rb);
-		} else if (config.num_samples == 0) {
-			piglit_require_extension("GL_ARB_texture_rectangle");
-			glBindTexture(GL_TEXTURE_RECTANGLE, color_tex);
-			glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER,
-					GL_NEAREST);
-			glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER,
-					GL_NEAREST);
-			glTexImage2D(GL_TEXTURE_RECTANGLE,
-				     0 /* level */,
-				     config.color_internalformat,
-				     config.width,
-				     config.height,
-				     0 /* border */,
-				     GL_RGBA /* format */,
-				     GL_BYTE /* type */,
-				     NULL /* data */);
-			glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
-					       GL_COLOR_ATTACHMENT0,
-					       GL_TEXTURE_RECTANGLE,
-					       color_tex,
-					       0 /* level */);
-		} else {
-			piglit_require_extension("GL_ARB_texture_multisample");
-			glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, color_tex);
-			glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
-						config.num_samples,
-						config.color_internalformat,
-						config.width,
-						config.height,
-						GL_TRUE /* fixed sample locations */);
-
-			glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
-					       GL_COLOR_ATTACHMENT0,
-					       GL_TEXTURE_2D_MULTISAMPLE,
-					       color_tex,
-					       0 /* level */);
-		}
-	}
-
-	/* Depth/stencil buffer(s) */
-	if (config.combine_depth_stencil) {
-		glBindRenderbuffer(GL_RENDERBUFFER, depth_rb);
-		glRenderbufferStorageMultisample(GL_RENDERBUFFER,
-						 config.num_samples,
-						 GL_DEPTH_STENCIL,
-						 config.width,
-						 config.height);
-		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
-					  GL_DEPTH_STENCIL_ATTACHMENT,
-					  GL_RENDERBUFFER, depth_rb);
-	} else {
-		if (config.stencil_internalformat != GL_NONE) {
-			glBindRenderbuffer(GL_RENDERBUFFER, stencil_rb);
-			glRenderbufferStorageMultisample(GL_RENDERBUFFER,
-							 config.num_samples,
-							 config.stencil_internalformat,
-							 config.width,
-							 config.height);
-			glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
-						  GL_STENCIL_ATTACHMENT,
-						  GL_RENDERBUFFER, stencil_rb);
-		}
-
-		if (config.depth_internalformat != GL_NONE) {
-			glBindRenderbuffer(GL_RENDERBUFFER, depth_rb);
-			glRenderbufferStorageMultisample(GL_RENDERBUFFER,
-							 config.num_samples,
-							 config.depth_internalformat,
-							 config.width,
-							 config.height);
-			glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
-						  GL_DEPTH_ATTACHMENT,
-						  GL_RENDERBUFFER, depth_rb);
-		}
-	}
-
-	bool success = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)
-		== GL_FRAMEBUFFER_COMPLETE;
-
-	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-
-	return success;
-}
-
-
-
-void
-Fbo::set_viewport()
-{
-	glViewport(0, 0, config.width, config.height);
-}
-
 void
 DownsampleProg::compile(int supersample_factor)
 {
@@ -396,942 +220,6 @@ DownsampleProg::run(const Fbo *src_fbo, int dest_width, int dest_height,
 	glDisable(GL_FRAMEBUFFER_SRGB);
 }
 
-void
-ManifestStencil::compile()
-{
-	static const char *vert =
-		"#version 120\n"
-		"attribute vec2 pos;\n"
-		"void main()\n"
-		"{\n"
-		"  gl_Position = vec4(pos, 0.0, 1.0);\n"
-		"}\n";
-
-	static const char *frag =
-		"#version 120\n"
-		"uniform vec4 color;\n"
-		"void main()\n"
-		"{\n"
-		"  gl_FragColor = color;\n"
-		"}\n";
-
-	/* Compile program */
-	prog = glCreateProgram();
-	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
-	glAttachShader(prog, vs);
-	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
-	glAttachShader(prog, fs);
-	glBindAttribLocation(prog, 0, "pos");
-	glLinkProgram(prog);
-	if (!piglit_link_check_status(prog)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	/* Set up uniforms */
-	glUseProgram(prog);
-	color_loc = glGetUniformLocation(prog, "color");
-
-	/* Set up vertex array object */
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	/* Set up vertex input buffer */
-	float vertex_data[4][2] = {
-		{ -1, -1 },
-		{ -1,  1 },
-		{  1,  1 },
-		{  1, -1 }
-	};
-	glGenVertexArrays(1, &vertex_buf);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
-		     GL_STATIC_DRAW);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
-			      (void *) 0);
-
-	/* Set up element input buffer to tesselate a quad into
-	 * triangles
-	 */
-	unsigned int indices[6] = { 0, 1, 2, 0, 2, 3 };
-	GLuint element_buf;
-	glGenBuffers(1, &element_buf);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buf);
-	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
-		     GL_STATIC_DRAW);
-}
-
-void
-ManifestStencil::run()
-{
-	static float colors[8][4] = {
-		{ 0.0, 0.0, 0.0, 1.0 },
-		{ 0.0, 0.0, 1.0, 1.0 },
-		{ 0.0, 1.0, 0.0, 1.0 },
-		{ 0.0, 1.0, 1.0, 1.0 },
-		{ 1.0, 0.0, 0.0, 1.0 },
-		{ 1.0, 0.0, 1.0, 1.0 },
-		{ 1.0, 1.0, 0.0, 1.0 },
-		{ 1.0, 1.0, 1.0, 1.0 }
-	};
-
-	glUseProgram(prog);
-	glBindVertexArray(vao);
-
-	glEnable(GL_STENCIL_TEST);
-	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
-	/* Clear the color buffer to 0, in case the stencil buffer
-	 * contains any values outside the range 0..7
-	 */
-	glClear(GL_COLOR_BUFFER_BIT);
-
-	for (int i = 0; i < 8; ++i) {
-		glStencilFunc(GL_EQUAL, i, 0xff);
-		glUniform4fv(color_loc, 1, colors[i]);
-		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void *) 0);
-	}
-
-	glDisable(GL_STENCIL_TEST);
-}
-
-void
-ManifestDepth::compile()
-{
-	static const char *vert =
-		"#version 120\n"
-		"attribute vec2 pos;\n"
-		"uniform float depth;\n"
-		"void main()\n"
-		"{\n"
-		"  gl_Position = vec4(pos, depth, 1.0);\n"
-		"}\n";
-
-	static const char *frag =
-		"#version 120\n"
-		"uniform vec4 color;\n"
-		"void main()\n"
-		"{\n"
-		"  gl_FragColor = color;\n"
-		"}\n";
-
-	/* Compile program */
-	prog = glCreateProgram();
-	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
-	glAttachShader(prog, vs);
-	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
-	glAttachShader(prog, fs);
-	glBindAttribLocation(prog, 0, "pos");
-	glLinkProgram(prog);
-	if (!piglit_link_check_status(prog)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	/* Set up uniforms */
-	glUseProgram(prog);
-	color_loc = glGetUniformLocation(prog, "color");
-	depth_loc = glGetUniformLocation(prog, "depth");
-
-	/* Set up vertex array object */
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	/* Set up vertex input buffer */
-	float vertex_data[4][2] = {
-		{ -1, -1 },
-		{ -1,  1 },
-		{  1,  1 },
-		{  1, -1 }
-	};
-	glGenVertexArrays(1, &vertex_buf);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
-		     GL_STATIC_DRAW);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
-			      (void *) 0);
-
-	/* Set up element input buffer to tesselate a quad into
-	 * triangles
-	 */
-	unsigned int indices[6] = { 0, 1, 2, 0, 2, 3 };
-	GLuint element_buf;
-	glGenBuffers(1, &element_buf);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buf);
-	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
-		     GL_STATIC_DRAW);
-}
-
-void
-ManifestDepth::run()
-{
-	static float colors[8][4] = {
-		{ 0.0, 0.0, 0.0, 1.0 },
-		{ 0.0, 0.0, 1.0, 1.0 },
-		{ 0.0, 1.0, 0.0, 1.0 },
-		{ 0.0, 1.0, 1.0, 1.0 },
-		{ 1.0, 0.0, 0.0, 1.0 },
-		{ 1.0, 0.0, 1.0, 1.0 },
-		{ 1.0, 1.0, 0.0, 1.0 },
-		{ 1.0, 1.0, 1.0, 1.0 }
-	};
-
-	glUseProgram(prog);
-	glBindVertexArray(vao);
-
-	glEnable(GL_DEPTH_TEST);
-	glDepthFunc(GL_LESS);
-	glEnable(GL_STENCIL_TEST);
-	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
-	glStencilFunc(GL_EQUAL, 0, 0xff);
-
-	/* Clear the stencil buffer to 0, leaving depth and color
-	 * buffers unchanged.
-	 */
-	glClear(GL_STENCIL_BUFFER_BIT);
-
-	for (int i = 0; i < 8; ++i) {
-		glUniform4fv(color_loc, 1, colors[i]);
-		glUniform1f(depth_loc, float(7 - 2*i)/8);
-		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void *) 0);
-	}
-
-	glDisable(GL_STENCIL_TEST);
-	glDisable(GL_DEPTH_TEST);
-}
-
-
-const float TestPattern::no_projection[4][4] = {
-	{ 1, 0, 0, 0 },
-	{ 0, 1, 0, 0 },
-	{ 0, 0, 1, 0 },
-	{ 0, 0, 0, 1 }
-};
-
-
-void Triangles::compile()
-{
-	/* Triangle coords within (-1,-1) to (1,1) rect */
-	static const float pos_within_tri[][2] = {
-		{ -0.5, -1.0 },
-		{  0.0,  1.0 },
-		{  0.5, -1.0 }
-	};
-
-	/* Number of triangle instances across (and down) */
-	int tris_across = 8;
-
-	/* Total number of triangles drawn */
-	num_tris = tris_across * tris_across;
-
-	/* Scaling factor uniformly applied to triangle coords */
-	float tri_scale = 0.8 / tris_across;
-
-	/* Amount each triangle should be rotated compared to prev */
-	float rotation_delta = M_PI * 2.0 / num_tris;
-
-	/* Final scaling factor */
-	float final_scale = 0.95;
-
-	static const char *vert =
-		"#version 120\n"
-		"attribute vec2 pos_within_tri;\n"
-		"uniform float tri_scale;\n"
-		"uniform float rotation_delta;\n"
-		"uniform int tris_across;\n"
-		"uniform float final_scale;\n"
-		"uniform mat4 proj;\n"
-		"uniform int tri_num; /* [0, num_tris) */\n"
-		"\n"
-		"void main()\n"
-		"{\n"
-		"  vec2 pos = tri_scale * pos_within_tri;\n"
-		"  float rotation = rotation_delta * tri_num;\n"
-		"  pos = mat2(cos(rotation), sin(rotation),\n"
-		"             -sin(rotation), cos(rotation)) * pos;\n"
-		"  int i = int(mod(float(tri_num), float(tris_across)));\n"
-		"  int j = tris_across - 1 - tri_num / tris_across;\n"
-		"  pos += (vec2(i, j) * 2.0 + 1.0) / tris_across - 1.0;\n"
-		"  pos *= final_scale;\n"
-		"  gl_Position = proj * vec4(pos, 0.0, 1.0);\n"
-		"}\n";
-
-	static const char *frag =
-		"#version 120\n"
-		"void main()\n"
-		"{\n"
-		"  gl_FragColor = vec4(1.0);\n"
-		"}\n";
-
-	/* Compile program */
-	prog = glCreateProgram();
-	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
-	glAttachShader(prog, vs);
-	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
-	glAttachShader(prog, fs);
-	glBindAttribLocation(prog, 0, "pos_within_tri");
-	glLinkProgram(prog);
-	if (!piglit_link_check_status(prog)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	/* Set up uniforms */
-	glUseProgram(prog);
-	glUniform1f(glGetUniformLocation(prog, "tri_scale"), tri_scale);
-	glUniform1f(glGetUniformLocation(prog, "rotation_delta"),
-		    rotation_delta);
-	glUniform1i(glGetUniformLocation(prog, "tris_across"), tris_across);
-	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
-	proj_loc = glGetUniformLocation(prog, "proj");
-	tri_num_loc = glGetUniformLocation(prog, "tri_num");
-
-	/* Set up vertex array object */
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	/* Set up vertex input buffer */
-	glGenBuffers(1, &vertex_buf);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(pos_within_tri), pos_within_tri,
-		     GL_STATIC_DRAW);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, ARRAY_SIZE(pos_within_tri[0]), GL_FLOAT,
-			      GL_FALSE, sizeof(pos_within_tri[0]), (void *) 0);
-}
-
-void Triangles::draw(const float (*proj)[4])
-{
-	glClear(GL_COLOR_BUFFER_BIT);
-
-	glUseProgram(prog);
-	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
-	glBindVertexArray(vao);
-	for (int tri_num = 0; tri_num < num_tris; ++tri_num) {
-		glUniform1i(tri_num_loc, tri_num);
-		glDrawArrays(GL_TRIANGLES, 0, 3);
-	}
-}
-
-
-InterpolationTestPattern::InterpolationTestPattern(const char *frag)
-	: frag(frag), viewport_size_loc(0)
-{
-}
-
-
-void
-InterpolationTestPattern::compile()
-{
-	static struct vertex_attributes {
-		float pos_within_tri[2];
-		float barycentric_coords[3];
-	} vertex_data[] = {
-		{ { -0.5, -1.0 }, { 1, 0, 0 } },
-		{ {  0.0,  1.0 }, { 0, 1, 0 } },
-		{ {  0.5, -1.0 }, { 0, 0, 1 } }
-	};
-
-	/* Number of triangle instances across (and down) */
-	int tris_across = 8;
-
-	/* Total number of triangles drawn */
-	num_tris = tris_across * tris_across;
-
-	/* Scaling factor uniformly applied to triangle coords */
-	float tri_scale = 0.8 / tris_across;
-
-	/* Amount each triangle should be rotated compared to prev */
-	float rotation_delta = M_PI * 2.0 / num_tris;
-
-	/* Final scaling factor */
-	float final_scale = 0.95;
-
-	static const char *vert =
-		"#version 120\n"
-		"attribute vec2 pos_within_tri;\n"
-		"attribute vec3 in_barycentric_coords;\n"
-		"varying vec3 barycentric_coords;\n"
-		"centroid varying vec3 barycentric_coords_centroid;\n"
-		"varying vec2 pixel_pos;\n"
-		"centroid varying vec2 pixel_pos_centroid;\n"
-		"uniform float tri_scale;\n"
-		"uniform float rotation_delta;\n"
-		"uniform int tris_across;\n"
-		"uniform float final_scale;\n"
-		"uniform mat4 proj;\n"
-		"uniform int tri_num; /* [0, num_tris) */\n"
-		"uniform ivec2 viewport_size;\n"
-		"\n"
-		"void main()\n"
-		"{\n"
-		"  vec2 pos = tri_scale * pos_within_tri;\n"
-		"  float rotation = rotation_delta * tri_num;\n"
-		"  pos = mat2(cos(rotation), sin(rotation),\n"
-		"             -sin(rotation), cos(rotation)) * pos;\n"
-		"  int i = int(mod(float(tri_num), float(tris_across)));\n"
-		"  int j = tris_across - 1 - tri_num / tris_across;\n"
-		"  pos += (vec2(i, j) * 2.0 + 1.0) / tris_across - 1.0;\n"
-		"  pos *= final_scale;\n"
-		"  gl_Position = proj * vec4(pos, 0.0, 1.0);\n"
-		"  barycentric_coords = barycentric_coords_centroid =\n"
-		"    in_barycentric_coords;\n"
-		"  pixel_pos = pixel_pos_centroid =\n"
-		"    vec2(viewport_size) * (pos + 1.0) / 2.0;\n"
-		"}\n";
-
-	/* Compile program */
-	prog = glCreateProgram();
-	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
-	glAttachShader(prog, vs);
-	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
-	glAttachShader(prog, fs);
-	glBindAttribLocation(prog, 0, "pos_within_tri");
-	glBindAttribLocation(prog, 1, "in_barycentric_coords");
-	glLinkProgram(prog);
-	if (!piglit_link_check_status(prog)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	/* Set up uniforms */
-	glUseProgram(prog);
-	glUniform1f(glGetUniformLocation(prog, "tri_scale"), tri_scale);
-	glUniform1f(glGetUniformLocation(prog, "rotation_delta"),
-		    rotation_delta);
-	glUniform1i(glGetUniformLocation(prog, "tris_across"), tris_across);
-	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
-	proj_loc = glGetUniformLocation(prog, "proj");
-	tri_num_loc = glGetUniformLocation(prog, "tri_num");
-	viewport_size_loc = glGetUniformLocation(prog, "viewport_size");
-
-	/* Set up vertex array object */
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	/* Set up vertex input buffer */
-	glGenBuffers(1, &vertex_buf);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
-		     GL_STATIC_DRAW);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, ARRAY_SIZE(vertex_data[0].pos_within_tri),
-			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
-			      (void *) offsetof(vertex_attributes,
-						pos_within_tri));
-	glEnableVertexAttribArray(1);
-	glVertexAttribPointer(1, ARRAY_SIZE(vertex_data[0].barycentric_coords),
-			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
-			      (void *) offsetof(vertex_attributes,
-						barycentric_coords));
-}
-
-
-void
-InterpolationTestPattern::draw(const float (*proj)[4])
-{
-	glUseProgram(prog);
-
-	/* Depending what the fragment shader does, it's possible that
-	 * viewport_size might get optimized away.  Only set it if it
-	 * didn't.
-	 */
-	if (viewport_size_loc != -1) {
-		GLint viewport_dims[4];
-		glGetIntegerv(GL_VIEWPORT, viewport_dims);
-		glUniform2i(viewport_size_loc, viewport_dims[2], viewport_dims[3]);
-	}
-
-	Triangles::draw(proj);
-}
-
-
-void Lines::compile()
-{
-	/* Line coords within (-1,-1) to (1,1) rect */
-	static const float pos_line[][2] = {
-		{ -0.8, -0.5 },
-		{  0.8, -0.5 }
-	};
-
-	/* Number of line instances across (and down) */
-	int lines_across = 4;
-
-	/* Total number of lines drawn */
-	num_lines = lines_across * lines_across;
-
-	/* Amount each line should be rotated compared to prev */
-	float rotation_delta = M_PI * 2.0 / num_lines;
-
-	/* Scaling factor uniformly applied to line coords */
-	float line_scale = 0.8 / lines_across;
-
-	/* Final scaling factor */
-	float final_scale = 0.95;
-
-	static const char *vert =
-		"#version 120\n"
-		"attribute vec2 pos_line;\n"
-		"uniform float line_scale;\n"
-		"uniform float rotation_delta;\n"
-		"uniform int lines_across;\n"
-		"uniform float final_scale;\n"
-		"uniform mat4 proj;\n"
-		"uniform int line_num;\n"
-		"\n"
-		"void main()\n"
-		"{\n"
-		"  vec2 pos = line_scale * pos_line;\n"
-		"  float rotation = rotation_delta * line_num;\n"
-		"  pos = mat2(cos(rotation), sin(rotation),\n"
-		"             -sin(rotation), cos(rotation)) * pos;\n"
-		"  int i = int(mod(float(line_num), float(lines_across)));\n"
-		"  int j = lines_across - 1 - line_num / lines_across;\n"
-		"  pos += (vec2(i, j) * 2.0 + 1.0) / lines_across - 1.0;\n"
-		"  pos *= final_scale;\n"
-		"  gl_Position = proj * vec4(pos, 0.0, 1.0);\n"
-		"}\n";
-
-	static const char *frag =
-		"#version 120\n"
-		"void main()\n"
-		"{\n"
-		"  gl_FragColor = vec4(1.0);\n"
-		"}\n";
-
-	/* Compile program */
-	prog = glCreateProgram();
-	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
-	glAttachShader(prog, vs);
-	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
-	glAttachShader(prog, fs);
-	glBindAttribLocation(prog, 0, "pos_line");
-	glLinkProgram(prog);
-	if (!piglit_link_check_status(prog)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	/* Set up uniforms */
-	glUseProgram(prog);
-	glUniform1f(glGetUniformLocation(prog, "line_scale"), line_scale);
-	glUniform1f(glGetUniformLocation(prog, "rotation_delta"),
-		    rotation_delta);
-	glUniform1i(glGetUniformLocation(prog, "lines_across"), lines_across);
-	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
-	proj_loc = glGetUniformLocation(prog, "proj");
-	line_num_loc = glGetUniformLocation(prog, "line_num");
-
-	/* Set up vertex array object */
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	/* Set up vertex input buffer */
-	glGenBuffers(1, &vertex_buf);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(pos_line), pos_line,
-		     GL_STATIC_DRAW);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, ARRAY_SIZE(pos_line[0]), GL_FLOAT,
-			      GL_FALSE, sizeof(pos_line[0]), (void *) 0);
-}
-
-void Lines::draw(const float (*proj)[4])
-{
-	glClear(GL_COLOR_BUFFER_BIT);
-	glUseProgram(prog);
-	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
-	glBindVertexArray(vao);
-	for (int line_num = 0; line_num < num_lines; ++line_num) {
-		/* Draws with line width = 0.25, 0.75, 1.25,
-		 * 1.75, 2.25, 2.75, 3.25, 3.75
-		 */
-		glLineWidth((1 + 2 * line_num) / 4.0);
-		glUniform1i(line_num_loc, line_num);
-		glDrawArrays(GL_LINES, 0, 2);
-	}
-}
-
-void Points::compile()
-{
-	/* Point coords within (-1,-1) to (1,1) rect */
-	static const float pos_point[2] = { -0.5, -0.5 };
-
-	/* Number of point instances across (and down) */
-	int points_across = 4;
-
-	/* Total number of points drawn */
-	num_points = points_across * points_across;
-
-	/* Scaling factor uniformly applied to point coords */
-	float point_scale = 0.8 / points_across;
-
-	/* Final scaling factor */
-	float final_scale = 0.95;
-
-	static const char *vert =
-		"#version 120\n"
-		"attribute vec2 pos_point;\n"
-		"uniform float point_scale;\n"
-		"uniform int points_across;\n"
-		"uniform float final_scale;\n"
-		"uniform mat4 proj;\n"
-		"uniform int point_num;\n"
-		"uniform float depth;\n"
-		"\n"
-		"void main()\n"
-		"{\n"
-		"  vec2 pos = point_scale * pos_point;\n"
-		"  int i = int(mod(float(point_num), float(points_across)));\n"
-		"  int j = points_across - 1 - point_num / points_across;\n"
-		"  pos += (vec2(i, j) * 2.0 + 1.0) / points_across - 1.0;\n"
-		"  pos *= final_scale;\n"
-		"  gl_Position = proj * vec4(pos, depth, 1.0);\n"
-		"}\n";
-
-	static const char *frag =
-		"#version 120\n"
-		"void main()\n"
-		"{\n"
-		"  gl_FragColor = vec4(1.0);\n"
-		"}\n";
-
-	/* Compile program */
-	prog = glCreateProgram();
-	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
-	glAttachShader(prog, vs);
-	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
-	glAttachShader(prog, fs);
-	glBindAttribLocation(prog, 0, "pos_point");
-	glLinkProgram(prog);
-	if (!piglit_link_check_status(prog)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	/* Set up uniforms */
-	glUseProgram(prog);
-	glUniform1f(glGetUniformLocation(prog, "point_scale"), point_scale);
-	glUniform1i(glGetUniformLocation(prog, "points_across"), points_across);
-	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
-	proj_loc = glGetUniformLocation(prog, "proj");
-	point_num_loc = glGetUniformLocation(prog, "point_num");
-	depth_loc = glGetUniformLocation(prog, "depth");
-
-	/* Set up vertex array object */
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	/* Set up vertex input buffer */
-	glGenBuffers(1, &vertex_buf);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(pos_point), pos_point,
-		     GL_STATIC_DRAW);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, ARRAY_SIZE(pos_point), GL_FLOAT,
-			      GL_FALSE, 0, (void *) 0);
-}
-
-void Points::draw(const float (*proj)[4])
-{
-	glClear(GL_COLOR_BUFFER_BIT);
-	glUseProgram(prog);
-	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
-	glBindVertexArray(vao);
-	glUniform1f(depth_loc, 0.0);
-	for (int point_num = 0; point_num < num_points; ++point_num) {
-		glPointSize((1.0 + 4 * point_num) / 4.0);
-		glUniform1i(point_num_loc, point_num);
-		glDrawArrays(GL_POINTS, 0, 1);
-	}
-}
-
-Sunburst::Sunburst()
-	: out_type(GL_UNSIGNED_NORMALIZED),
-	  compute_depth(false),
-	  prog(0),
-	  rotation_loc(0),
-	  vert_depth_loc(0),
-	  frag_depth_loc(0),
-	  proj_loc(0),
-	  draw_colors_loc(0),
-	  vao(0),
-	  num_tris(0),
-	  vertex_buf(0)
-{
-}
-
-
-/**
- * Determine the GLSL type that should be used for rendering, based on
- * out_type.
- */
-const char *
-Sunburst::get_out_type_glsl() const
-{
-	switch(out_type) {
-	case GL_INT:
-		return "ivec4";
-	case GL_UNSIGNED_INT:
-		return "uvec4";
-	case GL_UNSIGNED_NORMALIZED:
-	case GL_FLOAT:
-		return "vec4";
-	default:
-		printf("Unrecognized out_type: %s\n",
-		       piglit_get_gl_enum_name(out_type));
-		piglit_report_result(PIGLIT_FAIL);
-		return "UNKNOWN";
-	}
-}
-
-
-void Sunburst::compile()
-{
-	static struct vertex_attributes {
-		float pos_within_tri[2];
-		float barycentric_coords[3];
-	} vertex_data[] = {
-		{ { -0.3, -0.8 }, { 1, 0, 0 } },
-		{ {  0.0,  1.0 }, { 0, 1, 0 } },
-		{ {  0.3, -0.8 }, { 0, 0, 1 } }
-	};
-        bool need_glsl130 = out_type == GL_INT || out_type == GL_UNSIGNED_INT;
-
-	if (need_glsl130) {
-		piglit_require_gl_version(30);
-	}
-
-	/* Total number of triangles drawn */
-	num_tris = 7;
-
-	static const char *vert_template =
-		"#version %s\n"
-		"attribute vec2 pos_within_tri;\n"
-		"attribute vec3 in_barycentric_coords;\n"
-		"varying vec3 barycentric_coords;\n"
-		"uniform float rotation;\n"
-		"uniform float vert_depth;\n"
-		"uniform mat4 proj;\n"
-		"\n"
-		"void main()\n"
-		"{\n"
-		"  vec2 pos = pos_within_tri;\n"
-		"  pos = mat2(cos(rotation), sin(rotation),\n"
-		"             -sin(rotation), cos(rotation)) * pos;\n"
-		"  gl_Position = proj * vec4(pos, vert_depth, 1.0);\n"
-		"  barycentric_coords = in_barycentric_coords;\n"
-		"}\n";
-
-	static const char *frag_template =
-		"#version %s\n"
-		"#define OUT_TYPE %s\n"
-		"#define COMPUTE_DEPTH %s\n"
-		"uniform float frag_depth;\n"
-		"varying vec3 barycentric_coords;\n"
-		"uniform mat3x4 draw_colors;\n"
-		"#if __VERSION__ == 130\n"
-		"  out OUT_TYPE frag_out;\n"
-		"#endif\n"
-		"\n"
-		"void main()\n"
-		"{\n"
-		"#if __VERSION__ == 130\n"
-		"  frag_out = OUT_TYPE(draw_colors * barycentric_coords);\n"
-		"#else\n"
-		"  gl_FragColor = draw_colors * barycentric_coords;\n"
-		"#endif\n"
-		"#if COMPUTE_DEPTH\n"
-		"  gl_FragDepth = (frag_depth + 1.0) / 2.0;\n"
-		"#endif\n"
-		"}\n";
-
-	/* Compile program */
-	prog = glCreateProgram();
-	unsigned vert_alloc_len =
-		strlen(vert_template) + 4;
-	char *vert = (char *) malloc(vert_alloc_len);
-	sprintf(vert, vert_template, need_glsl130 ? "130" : "120");
-	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
-	free(vert);
-	glAttachShader(prog, vs);
-
-	const char *out_type_glsl = get_out_type_glsl();
-	unsigned frag_alloc_len =
-		strlen(frag_template) + strlen(out_type_glsl) + 4;
-	char *frag = (char *) malloc(frag_alloc_len);
-	sprintf(frag, frag_template, need_glsl130 ? "130" : "120",
-		out_type_glsl,
-		compute_depth ? "1" : "0");
-	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
-	free(frag);
-	glAttachShader(prog, fs);
-
-	glBindAttribLocation(prog, 0, "pos_within_tri");
-	glBindAttribLocation(prog, 1, "in_barycentric_coords");
-	if (need_glsl130) {
-		glBindFragDataLocation(prog, 0, "frag_out");
-	}
-	glLinkProgram(prog);
-	if (!piglit_link_check_status(prog)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	/* Set up uniforms */
-	glUseProgram(prog);
-	rotation_loc = glGetUniformLocation(prog, "rotation");
-	vert_depth_loc = glGetUniformLocation(prog, "vert_depth");
-	frag_depth_loc = glGetUniformLocation(prog, "frag_depth");
-	glUniform1f(vert_depth_loc, 0.0);
-	glUniform1f(frag_depth_loc, 0.0);
-	proj_loc = glGetUniformLocation(prog, "proj");
-	draw_colors_loc = glGetUniformLocation(prog, "draw_colors");
-
-	/* Set up vertex array object */
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	/* Set up vertex input buffer */
-	glGenBuffers(1, &vertex_buf);
-	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
-		     GL_STATIC_DRAW);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, ARRAY_SIZE(vertex_data[0].pos_within_tri),
-			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
-			      (void *) 0);
-	glEnableVertexAttribArray(1);
-	glVertexAttribPointer(1, ARRAY_SIZE(vertex_data[0].barycentric_coords),
-			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
-			      (void *) offsetof(vertex_attributes,
-						barycentric_coords));
-}
-
-
-ColorGradientSunburst::ColorGradientSunburst(GLenum out_type)
-{
-	this->out_type = out_type;
-}
-
-
-/**
- * Draw the color gradient sunburst, but instead of using color
- * components that range from 0.0 to 1.0, apply the given scaling
- * factor and offset to each color component.
- *
- * The offset is also applied when clearing the color buffer.
- */
-void
-ColorGradientSunburst::draw_with_scale_and_offset(const float (*proj)[4],
-						  float scale, float offset)
-{
-	switch (out_type) {
-	case GL_INT: {
-		int clear_color[4] = { offset, offset, offset, offset };
-		glClearBufferiv(GL_COLOR, 0, clear_color);
-		break;
-	}
-	case GL_UNSIGNED_INT: {
-		unsigned clear_color[4] = { offset, offset, offset, offset };
-		glClearBufferuiv(GL_COLOR, 0, clear_color);
-		break;
-	}
-	case GL_UNSIGNED_NORMALIZED:
-	case GL_FLOAT: {
-		glClearColor(offset, offset, offset, offset);
-		glClear(GL_COLOR_BUFFER_BIT);
-		break;
-	}
-	default:
-		printf("Unrecognized out_type: %s\n",
-		       piglit_get_gl_enum_name(out_type));
-		piglit_report_result(PIGLIT_FAIL);
-		break;
-	}
-
-	glUseProgram(prog);
-	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
-	float draw_colors[3][4] =
-		{ { 1, 0, 0, 1.0 }, { 0, 1, 0, 0.5 }, { 0, 0, 1, 1.0 } };
-	for (int i = 0; i < 3; ++i) {
-		for (int j = 0; j < 4; ++j) {
-			draw_colors[i][j] = scale * draw_colors[i][j] + offset;
-		}
-	}
-	glUniformMatrix3x4fv(draw_colors_loc, 1, GL_FALSE,
-			     &draw_colors[0][0]);
-	glBindVertexArray(vao);
-	for (int i = 0; i < num_tris; ++i) {
-		glUniform1f(rotation_loc, M_PI * 2.0 * i / num_tris);
-		glDrawArrays(GL_TRIANGLES, 0, 3);
-	}
-}
-
-
-void
-ColorGradientSunburst::draw(const float (*proj)[4])
-{
-	draw_with_scale_and_offset(proj, 1.0, 0.0);
-}
-
-
-void
-StencilSunburst::draw(const float (*proj)[4])
-{
-	glEnable(GL_STENCIL_TEST);
-	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-
-	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
-	glUseProgram(prog);
-	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
-	glBindVertexArray(vao);
-	for (int i = 0; i < num_tris; ++i) {
-		glStencilFunc(GL_ALWAYS, i+1, 0xff);
-		glUniform1f(rotation_loc, M_PI * 2.0 * i / num_tris);
-		glDrawArrays(GL_TRIANGLES, 0, 3);
-	}
-
-	glDisable(GL_STENCIL_TEST);
-}
-
-
-DepthSunburst::DepthSunburst(bool compute_depth)
-{
-	this->compute_depth = compute_depth;
-}
-
-
-void
-DepthSunburst::draw(const float (*proj)[4])
-{
-	glEnable(GL_DEPTH_TEST);
-	glDepthFunc(GL_LESS);
-
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-	glUseProgram(prog);
-	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
-	glBindVertexArray(vao);
-	for (int i = 0; i < num_tris; ++i) {
-		/* Draw triangles in a haphazard order so we can
-		 * verify that depth comparisons sort them out
-		 * properly.
-		 */
-		int triangle_to_draw = (i * 3) % num_tris;
-
-		/* Note: with num_tris == 7, this causes us to draw
-		 * triangles at depths of 3/4, 1/2, -1/4, 0, 1/4, 1/2,
-		 * and 3/4.
-		 */
-		glUniform1f(compute_depth ? frag_depth_loc : vert_depth_loc,
-			    float(num_tris - triangle_to_draw * 2 - 1)
-			    / (num_tris + 1));
-
-		glUniform1f(rotation_loc,
-			    M_PI * 2.0 * triangle_to_draw / num_tris);
-		glDrawArrays(GL_TRIANGLES, 0, 3);
-	}
-
-	glDisable(GL_DEPTH_TEST);
-}
-
 Stats::Stats()
 	: count(0), sum_squared_error(0.0)
 {
diff --git a/tests/spec/ext_framebuffer_multisample/common.h b/tests/spec/ext_framebuffer_multisample/common.h
index 710d77e..eee31f0 100644
--- a/tests/spec/ext_framebuffer_multisample/common.h
+++ b/tests/spec/ext_framebuffer_multisample/common.h
@@ -27,6 +27,8 @@
  */
 
 #include "piglit-util-gl-common.h"
+#include "piglit-test-pattern.h"
+#include "piglit-fbo.h"
 #include "math.h"
 
 enum test_type_enum {
@@ -39,115 +41,6 @@ enum test_type_enum {
 };
 
 /**
- * Information needed to configure a framebuffer object for MSAA
- * testing.
- */
-class FboConfig
-{
-public:
-	FboConfig(int num_samples, int width, int height);
-
-	int num_samples;
-	int width;
-	int height;
-
-	/**
-	 * True if a single renderbuffer should be used as the backing
-	 * store for both the depth and stencil attachment points.
-	 * Defaults to true.
-	 */
-	bool combine_depth_stencil;
-
-	/**
-	 * True if a texture should be used as the backing store for
-	 * the color attachment point, false if a renderbuffer should
-	 * be used.  Defaults to false.
-	 */
-	bool attach_texture;
-
-	/**
-	 * Internalformat that should be used for the color buffer, or
-	 * GL_NONE if no color buffer should be used.  Defaults to
-	 * GL_RGBA.
-	 */
-	GLenum color_internalformat;
-
-	/**
-	 * Internalformat that should be used for the depth buffer, or
-	 * GL_NONE if no depth buffer should be used.  Ignored if
-	 * combine_depth_stencil is true.  Defaults to
-	 * GL_DEPTH_COMPONENT24.
-	 */
-	GLenum depth_internalformat;
-
-	/**
-	 * Internalformat that should be used for the stencil buffer,
-	 * or GL_NONE if no stencil buffer should be used.  Ignored if
-	 * combine_depth_stencil is true.  Defaults to
-	 * GL_STENCIL_INDEX8.
-	 */
-	GLenum stencil_internalformat;
-};
-
-/**
- * Data structure representing one of the framebuffer objects used in
- * the test.
- *
- * For the supersampled framebuffer object we use a texture as the
- * backing store for the color buffer so that we can use a fragment
- * shader to blend down to the reference image.
- */
-class Fbo
-{
-public:
-	Fbo();
-
-	void set_samples(int num_samples);
-	void setup(const FboConfig &new_config);
-	bool try_setup(const FboConfig &new_config);
-
-	void set_viewport();
-
-	FboConfig config;
-	GLuint handle;
-
-	/**
-	 * If config.attach_texture is true, the backing store for the
-	 * color buffer.
-	 */
-	GLuint color_tex;
-
-	/**
-	 * If config.attach_texture is false, the backing store for
-	 * the color buffer.
-	 */
-	GLuint color_rb;
-
-	/**
-	 * If config.combine_depth_stencil is true, the backing store
-	 * for the depth/stencil buffer.  If
-	 * config.combine_depth_stencil is false, the backing store
-	 * for the depth buffer.
-	 */
-	GLuint depth_rb;
-
-	/**
-	 * If config.combine_depth_stencil is false, the backing store
-	 * for the stencil buffer.
-	 */
-	GLuint stencil_rb;
-
-private:
-	void generate_gl_objects();
-
-	/**
-	 * True if generate_gl_objects has been called and color_tex,
-	 * color_rb, depth_rb, and stencil_rb have been initialized.
-	 */
-	bool gl_objects_generated;
-};
-
-/**
  * Fragment shader program we apply to the supersampled color buffer
  * to produce the reference image.  This program manually blends each
  * 16x16 block of samples in the supersampled color buffer down to a
@@ -167,298 +60,6 @@ private:
 };
 
 /**
- * There are two programs used to "manifest" an auxiliary buffer,
- * turning it into visible colors: one for manifesting the stencil
- * buffer, and one for manifesting the depth buffer.  This is the base
- * class that they both derive from.
- */
-class ManifestProgram
-{
-public:
-	virtual void compile() = 0;
-	virtual void run() = 0;
-};
-
-/**
- * Program we use to manifest the stencil buffer.
- *
- * This program operates by repeatedly drawing over the entire buffer
- * using the stencil function "EQUAL", and a different color each
- * time.  This causes stencil values from 0 to 7 to manifest as colors
- * (black, blue, green, cyan, red, magenta, yellow, white).
- */
-class ManifestStencil : public ManifestProgram
-{
-public:
-	virtual void compile();
-	virtual void run();
-
-private:
-	GLint prog;
-	GLint color_loc;
-	GLuint vertex_buf;
-	GLuint vao;
-};
-
-/**
- * Program we use to manifest the depth buffer.
- *
- * This program operates by repeatedly drawing over the entire buffer
- * at decreasing depth values with depth test enabled; the stencil
- * function is configured to "EQUAL" with a stencil op of "INCR", so
- * that after a sample passes the depth test, its stencil value will
- * be incremented and it will fail the stencil test on later draws.
- * As a result, depth values from back to front will manifest as
- * colors (black, blue, green, cyan, red, magenta, yellow, white).
- */
-class ManifestDepth : public ManifestProgram
-{
-public:
-	virtual void compile();
-	virtual void run();
-
-private:
-	GLint prog;
-	GLint color_loc;
-	GLint depth_loc;
-	GLuint vertex_buf;
-	GLuint vao;
-};
-
-/**
- * There are three programs used to draw a test pattern, depending on
- * whether we are testing the color buffer, the depth buffer, or the
- * stencil buffer.  This is the base class that they all derive from.
- */
-class TestPattern
-{
-public:
-	virtual void compile() = 0;
-
-	/**
-	 * Draw the test pattern, applying the given projection matrix
-	 * to vertex coordinates.  The projection matrix is in
-	 * row-major order.
-	 *
-	 * If no projection transformation is needed, pass
-	 * TestPattern::no_projection for \c proj.
-	 */
-	virtual void draw(const float (*proj)[4]) = 0;
-
-	static const float no_projection[4][4];
-};
-
-/**
- * Program we use to draw a test pattern into the color buffer.
- *
- * This program draws a grid of small disjoint triangles, each rotated
- * at a different angle.  This ensures that the image will have a
- * large number of edges at different angles, so that we'll thoroughly
- * exercise antialiasing.
- */
-class Triangles : public TestPattern
-{
-public:
-	virtual void compile();
-	virtual void draw(const float (*proj)[4]);
-
-protected:
-	GLint prog;
-	GLuint vertex_buf;
-	GLuint vao;
-	GLint proj_loc;
-	GLint tri_num_loc;
-	int num_tris;
-};
-
-
-/**
- * Program we use to test that interpolation works properly.
- *
- * This program draws the same sequence of small triangles as the
- * Triangles program, but it's capable of coloring the triangles in
- * various ways based on the fragment program provided to the
- * constructor.
- *
- * The fragment program has access to the following variables:
- *
- * - in vec3 barycentric_coords: barycentric coordinates of the
- *   triangle being drawn, normally interpolated.
- *
- * - centroid in vec3 barycentric_coords_centroid: same as
- *   barycentric_coords, but centroid interpolated.
- *
- * - in vec2 pixel_pos: pixel coordinate ((0,0) to (viewport_width,
- *   viewport_height)), normally interpolated.
- *
- * - centroid in vec2 pixel_pos_centroid: same as pixel_pos, but
- *   centroid interpolated.
- */
-class InterpolationTestPattern : public Triangles
-{
-public:
-	explicit InterpolationTestPattern(const char *frag);
-	virtual void compile();
-	virtual void draw(const float (*proj)[4]);
-
-private:
-	const char *frag;
-	GLint viewport_size_loc;
-};
-
-
-/**
- * Program we use to draw a test pattern into the color buffer.
- *
- * This program draws a sequence of points with varied sizes. This ensures
- * antialiasing works well with all point sizes.
- */
-class Points : public TestPattern
-{
-public:
-	virtual void compile();
-	virtual void draw(const float (*proj)[4]);
-
-private:
-	GLint prog;
-	GLuint vao;
-	GLint proj_loc;
-	GLint depth_loc;
-	GLint point_num_loc;
-	GLuint vertex_buf;
-	int num_points;
-};
-
-/**
- * Program we use to draw a test pattern into the color buffer.
- *
- * This program draws a sequence of lines with varied width. This ensures
- * antialiasing works well with all line widths.
- */
-class Lines : public TestPattern
-{
-public:
-	virtual void compile();
-	virtual void draw(const float (*proj)[4]);
-
-private:
-	GLint prog;
-	GLuint vao;
-	GLint proj_loc;
-	GLint line_num_loc;
-	GLuint vertex_buf;
-	int num_lines;
-};
-
-/**
- * Program we use to draw a test pattern into the depth and stencil
- * buffers.
- *
- * This program draws a "sunburst" pattern consisting of 7 overlapping
- * triangles, each at a different angle.  This ensures that the
- * triangles overlap in a complex way, with the edges between them
- * covering a a large number of different angles, so that we'll
- * thoroughly exercise antialiasing.
- *
- * This program is further specialized into depth and stencil variants.
- */
-class Sunburst : public TestPattern
-{
-public:
-	Sunburst();
-
-	virtual void compile();
-
-	/**
-	 * Type of color buffer being rendered into.  Should be one of
-	 * the following enum values: GL_FLOAT,
-	 * GL_UNSIGNED_NORMALIZED, GL_UNSIGNED_INT, or GL_INT.
-	 *
-	 * Defaults to GL_UNSIGNED_NORMALIZED.
-	 */
-	GLenum out_type;
-
-	/**
-	 * Whether or not the fragment shader should output a depth
-	 * value.
-	 *
-	 * Defaults to false.
-	 */
-	bool compute_depth;
-
-protected:
-	GLint prog;
-	GLint rotation_loc;
-	GLint vert_depth_loc;
-	GLint frag_depth_loc;
-	GLint proj_loc;
-	GLint draw_colors_loc;
-	GLuint vao;
-	int num_tris;
-
-private:
-	const char *get_out_type_glsl() const;
-
-	GLuint vertex_buf;
-};
-
-/**
- * Program that draws a test pattern into the color buffer.
- *
- * This program draws triangles using a variety of colors and
- * gradients.
- *
- * This program is capable of drawing to floating point, integer, and
- * unsigned integer framebuffers, controlled by the out_type
- * constructor parameter, which should be GL_FLOAT,
- * GL_UNSIGNED_NORMALIZED, GL_UNSIGNED_INT, or GL_INT.
- */
-class ColorGradientSunburst : public Sunburst
-{
-public:
-	explicit ColorGradientSunburst(GLenum out_type);
-
-	virtual void draw(const float (*proj)[4]);
-
-	void draw_with_scale_and_offset(const float (*proj)[4],
-					float scale, float offset);
-};
-
-/**
- * Program we use to draw a test pattern into the stencil buffer.
- *
- * The triangles in this sunburst are drawn back-to-front, using no
- * depth testing.  Each triangle is drawn using a different stencil
- * value.
- */
-class StencilSunburst : public Sunburst
-{
-public:
-	virtual void draw(const float (*proj)[4]);
-};
-
-/**
- * Program we use to draw a test pattern into the depth buffer.
- *
- * The triangles in this sunburst are drawn at a series of different
- * depth values, with depth testing enabled.  They are drawn in an
- * arbitrary non-consecutive order, to verify that depth testing
- * properly sorts the surfaces into front-to-back order.
- *
- * If the constructor parameter compute_depth is true, the depth value
- * is determined using a fragment shader output.  If it is false, it
- * is determined by the z value of the vertex shader gl_Position
- * output.
- */
-class DepthSunburst : public Sunburst
-{
-public:
-	explicit DepthSunburst(bool compute_depth = false);
-
-	virtual void draw(const float (*proj)[4]);
-};
-
-/**
  * Data structure for keeping track of statistics on pixel accuracy.
  *
  * We keep track of the number of pixels tested, and the sum of the
diff --git a/tests/util/CMakeLists.gl.txt b/tests/util/CMakeLists.gl.txt
index 10be17a..d8fb32c 100644
--- a/tests/util/CMakeLists.gl.txt
+++ b/tests/util/CMakeLists.gl.txt
@@ -6,6 +6,8 @@ set(UTIL_GL_SOURCES
 	piglit-shader-gl.c
 	piglit-util-gl-enum.c
 	piglit-util-gl.c
+	piglit-test-pattern.cpp
+	piglit-fbo.cpp
 	piglit-vbo.cpp
 	sized-internalformats.c
 	minmax-test.c
diff --git a/tests/util/piglit-fbo.cpp b/tests/util/piglit-fbo.cpp
new file mode 100644
index 0000000..f466f42
--- /dev/null
+++ b/tests/util/piglit-fbo.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2013 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 piglit-fbo.cpp
+ *
+ * This file defines the functions which can be utilized to develop
+ * new piglit test cases. These functions initialize a framebuffer
+ * object based on paramaters passed.
+ */
+#include "piglit-fbo.h"
+
+FboConfig::FboConfig(int num_samples, int width, int height)
+	: num_samples(num_samples),
+	  width(width),
+	  height(height),
+	  combine_depth_stencil(true),
+	  attach_texture(false),
+	  color_internalformat(GL_RGBA),
+	  depth_internalformat(GL_DEPTH_COMPONENT24),
+	  stencil_internalformat(GL_STENCIL_INDEX8)
+{
+}
+
+Fbo::Fbo()
+	: config(0, 0, 0), /* will be overwritten on first call to setup() */
+	  handle(0),
+	  color_tex(0),
+	  color_rb(0),
+	  depth_rb(0),
+	  stencil_rb(0),
+	  gl_objects_generated(false)
+{
+}
+
+void
+Fbo::generate_gl_objects(void)
+{
+	glGenFramebuffers(1, &handle);
+	glGenTextures(1, &color_tex);
+	glGenRenderbuffers(1, &color_rb);
+	glGenRenderbuffers(1, &depth_rb);
+	glGenRenderbuffers(1, &stencil_rb);
+	gl_objects_generated = true;
+}
+
+void
+Fbo::set_samples(int num_samples)
+{
+	FboConfig new_config = this->config;
+	new_config.num_samples = num_samples;
+	setup(new_config);
+}
+
+/**
+ * Modify the state of the framebuffer object to reflect the state in
+ * new_config.  if the resulting framebuffer is incomplete, terminate
+ * the test.
+ */
+void
+Fbo::setup(const FboConfig &new_config)
+{
+	if (!try_setup(new_config)) {
+		printf("Framebuffer not complete\n");
+		piglit_report_result(PIGLIT_SKIP);
+	}
+}
+
+/**
+ * Modify the state of the framebuffer object to reflect the state in
+ * config.  Return true if the resulting framebuffer is complete,
+ * false otherwise.
+ */
+bool
+Fbo::try_setup(const FboConfig &new_config)
+{
+	this->config = new_config;
+
+	if (!gl_objects_generated)
+		generate_gl_objects();
+
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, handle);
+
+	/* Color buffer */
+	if (config.color_internalformat != GL_NONE) {
+		if (!config.attach_texture) {
+			glBindRenderbuffer(GL_RENDERBUFFER, color_rb);
+			glRenderbufferStorageMultisample(GL_RENDERBUFFER,
+							 config.num_samples,
+							 config.color_internalformat,
+							 config.width,
+							 config.height);
+			glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
+						  GL_COLOR_ATTACHMENT0,
+						  GL_RENDERBUFFER, color_rb);
+		} else if (config.num_samples == 0) {
+			piglit_require_extension("GL_ARB_texture_rectangle");
+			glBindTexture(GL_TEXTURE_RECTANGLE, color_tex);
+			glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER,
+					GL_NEAREST);
+			glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER,
+					GL_NEAREST);
+			glTexImage2D(GL_TEXTURE_RECTANGLE,
+				     0 /* level */,
+				     config.color_internalformat,
+				     config.width,
+				     config.height,
+				     0 /* border */,
+				     GL_RGBA /* format */,
+				     GL_BYTE /* type */,
+				     NULL /* data */);
+			glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
+					       GL_COLOR_ATTACHMENT0,
+					       GL_TEXTURE_RECTANGLE,
+					       color_tex,
+					       0 /* level */);
+		} else {
+			piglit_require_extension("GL_ARB_texture_multisample");
+			glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, color_tex);
+			glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
+						config.num_samples,
+						config.color_internalformat,
+						config.width,
+						config.height,
+						GL_TRUE /* fixed sample locations */);
+
+			glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
+					       GL_COLOR_ATTACHMENT0,
+					       GL_TEXTURE_2D_MULTISAMPLE,
+					       color_tex,
+					       0 /* level */);
+		}
+	}
+
+	/* Depth/stencil buffer(s) */
+	if (config.combine_depth_stencil) {
+		glBindRenderbuffer(GL_RENDERBUFFER, depth_rb);
+		glRenderbufferStorageMultisample(GL_RENDERBUFFER,
+						 config.num_samples,
+						 GL_DEPTH_STENCIL,
+						 config.width,
+						 config.height);
+		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
+					  GL_DEPTH_STENCIL_ATTACHMENT,
+					  GL_RENDERBUFFER, depth_rb);
+	} else {
+		if (config.stencil_internalformat != GL_NONE) {
+			glBindRenderbuffer(GL_RENDERBUFFER, stencil_rb);
+			glRenderbufferStorageMultisample(GL_RENDERBUFFER,
+							 config.num_samples,
+							 config.stencil_internalformat,
+							 config.width,
+							 config.height);
+			glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
+						  GL_STENCIL_ATTACHMENT,
+						  GL_RENDERBUFFER, stencil_rb);
+		}
+
+		if (config.depth_internalformat != GL_NONE) {
+			glBindRenderbuffer(GL_RENDERBUFFER, depth_rb);
+			glRenderbufferStorageMultisample(GL_RENDERBUFFER,
+							 config.num_samples,
+							 config.depth_internalformat,
+							 config.width,
+							 config.height);
+			glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
+						  GL_DEPTH_ATTACHMENT,
+						  GL_RENDERBUFFER, depth_rb);
+		}
+	}
+
+	bool success = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)
+		== GL_FRAMEBUFFER_COMPLETE;
+
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+
+	return success;
+}
+
+void
+Fbo::set_viewport()
+{
+	glViewport(0, 0, config.width, config.height);
+}
diff --git a/tests/util/piglit-fbo.h b/tests/util/piglit-fbo.h
new file mode 100644
index 0000000..87aebcf
--- /dev/null
+++ b/tests/util/piglit-fbo.h
@@ -0,0 +1,139 @@
+/* Copyright © 2013 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 piglit-fbo.h
+ * This file declares classes to initialize a framebuffer object as per piglit
+ * test's requirements.
+ */
+
+#include "piglit-util-gl-common.h"
+#include "math.h"
+
+/**
+ * Information needed to configure a framebuffer object for MSAA
+ * testing.
+ */
+class FboConfig
+{
+public:
+	FboConfig(int num_samples, int width, int height);
+
+	int num_samples;
+	int width;
+	int height;
+
+	/**
+	 * True if a single renderbuffer should be used as the backing
+	 * store for both the depth and stencil attachment points.
+	 * Defaults to true.
+	 */
+	bool combine_depth_stencil;
+
+	/**
+	 * True if a texture should be used as the backing store for
+	 * the color attachment point, false if a renderbuffer should
+	 * be used.  Defaults to false.
+	 */
+	bool attach_texture;
+
+	/**
+	 * Internalformat that should be used for the color buffer, or
+	 * GL_NONE if no color buffer should be used.  Defaults to
+	 * GL_RGBA.
+	 */
+	GLenum color_internalformat;
+
+	/**
+	 * Internalformat that should be used for the depth buffer, or
+	 * GL_NONE if no depth buffer should be used.  Ignored if
+	 * combine_depth_stencil is true.  Defaults to
+	 * GL_DEPTH_COMPONENT24.
+	 */
+	GLenum depth_internalformat;
+
+	/**
+	 * Internalformat that should be used for the stencil buffer,
+	 * or GL_NONE if no stencil buffer should be used.  Ignored if
+	 * combine_depth_stencil is true.  Defaults to
+	 * GL_STENCIL_INDEX8.
+	 */
+	GLenum stencil_internalformat;
+};
+
+/**
+ * Data structure representing one of the framebuffer objects used in
+ * the test.
+ *
+ * For the supersampled framebuffer object we use a texture as the
+ * backing store for the color buffer so that we can use a fragment
+ * shader to blend down to the reference image.
+ */
+class Fbo
+{
+public:
+	Fbo();
+
+	void set_samples(int num_samples);
+	void setup(const FboConfig &new_config);
+	bool try_setup(const FboConfig &new_config);
+
+	void set_viewport();
+
+	FboConfig config;
+	GLuint handle;
+
+	/**
+	 * If config.attach_texture is true, the backing store for the
+	 * color buffer.
+	 */
+	GLuint color_tex;
+
+	/**
+	 * If config.attach_texture is false, the backing store for
+	 * the color buffer.
+	 */
+	GLuint color_rb;
+
+	/**
+	 * If config.combine_depth_stencil is true, the backing store
+	 * for the depth/stencil buffer.  If
+	 * config.combine_depth_stencil is false, the backing store
+	 * for the depth buffer.
+	 */
+	GLuint depth_rb;
+
+	/**
+	 * If config.combine_depth_stencil is false, the backing store
+	 * for the stencil buffer.
+	 */
+	GLuint stencil_rb;
+
+private:
+	void generate_gl_objects();
+
+	/**
+	 * True if generate_gl_objects has been called and color_tex,
+	 * color_rb, depth_rb, and stencil_rb have been initialized.
+	 */
+	bool gl_objects_generated;
+};
diff --git a/tests/util/piglit-test-pattern.cpp b/tests/util/piglit-test-pattern.cpp
new file mode 100644
index 0000000..b7c8b61
--- /dev/null
+++ b/tests/util/piglit-test-pattern.cpp
@@ -0,0 +1,967 @@
+/*
+ * Copyright © 2013 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 piglit-test-pattern.cpp
+ *
+ * This file defines the functions which can be utilized to draw test patterns
+ * in to color, depth or stencil buffers.
+ *
+ */
+#include "piglit-test-pattern.h"
+
+const float TestPattern::no_projection[4][4] = {
+	{ 1, 0, 0, 0 },
+	{ 0, 1, 0, 0 },
+	{ 0, 0, 1, 0 },
+	{ 0, 0, 0, 1 }
+};
+
+
+void Triangles::compile()
+{
+	/* Triangle coords within (-1,-1) to (1,1) rect */
+	static const float pos_within_tri[][2] = {
+		{ -0.5, -1.0 },
+		{  0.0,  1.0 },
+		{  0.5, -1.0 }
+	};
+
+	/* Number of triangle instances across (and down) */
+	int tris_across = 8;
+
+	/* Total number of triangles drawn */
+	num_tris = tris_across * tris_across;
+
+	/* Scaling factor uniformly applied to triangle coords */
+	float tri_scale = 0.8 / tris_across;
+
+	/* Amount each triangle should be rotated compared to prev */
+	float rotation_delta = M_PI * 2.0 / num_tris;
+
+	/* Final scaling factor */
+	float final_scale = 0.95;
+
+	static const char *vert =
+		"#version 120\n"
+		"attribute vec2 pos_within_tri;\n"
+		"uniform float tri_scale;\n"
+		"uniform float rotation_delta;\n"
+		"uniform int tris_across;\n"
+		"uniform float final_scale;\n"
+		"uniform mat4 proj;\n"
+		"uniform int tri_num; /* [0, num_tris) */\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"  vec2 pos = tri_scale * pos_within_tri;\n"
+		"  float rotation = rotation_delta * tri_num;\n"
+		"  pos = mat2(cos(rotation), sin(rotation),\n"
+		"             -sin(rotation), cos(rotation)) * pos;\n"
+		"  int i = int(mod(float(tri_num), float(tris_across)));\n"
+		"  int j = tris_across - 1 - tri_num / tris_across;\n"
+		"  pos += (vec2(i, j) * 2.0 + 1.0) / tris_across - 1.0;\n"
+		"  pos *= final_scale;\n"
+		"  gl_Position = proj * vec4(pos, 0.0, 1.0);\n"
+		"}\n";
+
+	static const char *frag =
+		"#version 120\n"
+		"void main()\n"
+		"{\n"
+		"  gl_FragColor = vec4(1.0);\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	glAttachShader(prog, vs);
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	glAttachShader(prog, fs);
+	glBindAttribLocation(prog, 0, "pos_within_tri");
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	glUniform1f(glGetUniformLocation(prog, "tri_scale"), tri_scale);
+	glUniform1f(glGetUniformLocation(prog, "rotation_delta"),
+		    rotation_delta);
+	glUniform1i(glGetUniformLocation(prog, "tris_across"), tris_across);
+	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
+	proj_loc = glGetUniformLocation(prog, "proj");
+	tri_num_loc = glGetUniformLocation(prog, "tri_num");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	glGenBuffers(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(pos_within_tri), pos_within_tri,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, ARRAY_SIZE(pos_within_tri[0]), GL_FLOAT,
+			      GL_FALSE, sizeof(pos_within_tri[0]), (void *) 0);
+}
+
+void Triangles::draw(const float (*proj)[4])
+{
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glUseProgram(prog);
+	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
+	glBindVertexArray(vao);
+	for (int tri_num = 0; tri_num < num_tris; ++tri_num) {
+		glUniform1i(tri_num_loc, tri_num);
+		glDrawArrays(GL_TRIANGLES, 0, 3);
+	}
+}
+
+
+InterpolationTestPattern::InterpolationTestPattern(const char *frag)
+	: frag(frag), viewport_size_loc(0)
+{
+}
+
+
+void
+InterpolationTestPattern::compile()
+{
+	static struct vertex_attributes {
+		float pos_within_tri[2];
+		float barycentric_coords[3];
+	} vertex_data[] = {
+		{ { -0.5, -1.0 }, { 1, 0, 0 } },
+		{ {  0.0,  1.0 }, { 0, 1, 0 } },
+		{ {  0.5, -1.0 }, { 0, 0, 1 } }
+	};
+
+	/* Number of triangle instances across (and down) */
+	int tris_across = 8;
+
+	/* Total number of triangles drawn */
+	num_tris = tris_across * tris_across;
+
+	/* Scaling factor uniformly applied to triangle coords */
+	float tri_scale = 0.8 / tris_across;
+
+	/* Amount each triangle should be rotated compared to prev */
+	float rotation_delta = M_PI * 2.0 / num_tris;
+
+	/* Final scaling factor */
+	float final_scale = 0.95;
+
+	static const char *vert =
+		"#version 120\n"
+		"attribute vec2 pos_within_tri;\n"
+		"attribute vec3 in_barycentric_coords;\n"
+		"varying vec3 barycentric_coords;\n"
+		"centroid varying vec3 barycentric_coords_centroid;\n"
+		"varying vec2 pixel_pos;\n"
+		"centroid varying vec2 pixel_pos_centroid;\n"
+		"uniform float tri_scale;\n"
+		"uniform float rotation_delta;\n"
+		"uniform int tris_across;\n"
+		"uniform float final_scale;\n"
+		"uniform mat4 proj;\n"
+		"uniform int tri_num; /* [0, num_tris) */\n"
+		"uniform ivec2 viewport_size;\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"  vec2 pos = tri_scale * pos_within_tri;\n"
+		"  float rotation = rotation_delta * tri_num;\n"
+		"  pos = mat2(cos(rotation), sin(rotation),\n"
+		"             -sin(rotation), cos(rotation)) * pos;\n"
+		"  int i = int(mod(float(tri_num), float(tris_across)));\n"
+		"  int j = tris_across - 1 - tri_num / tris_across;\n"
+		"  pos += (vec2(i, j) * 2.0 + 1.0) / tris_across - 1.0;\n"
+		"  pos *= final_scale;\n"
+		"  gl_Position = proj * vec4(pos, 0.0, 1.0);\n"
+		"  barycentric_coords = barycentric_coords_centroid =\n"
+		"    in_barycentric_coords;\n"
+		"  pixel_pos = pixel_pos_centroid =\n"
+		"    vec2(viewport_size) * (pos + 1.0) / 2.0;\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	glAttachShader(prog, vs);
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	glAttachShader(prog, fs);
+	glBindAttribLocation(prog, 0, "pos_within_tri");
+	glBindAttribLocation(prog, 1, "in_barycentric_coords");
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	glUniform1f(glGetUniformLocation(prog, "tri_scale"), tri_scale);
+	glUniform1f(glGetUniformLocation(prog, "rotation_delta"),
+		    rotation_delta);
+	glUniform1i(glGetUniformLocation(prog, "tris_across"), tris_across);
+	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
+	proj_loc = glGetUniformLocation(prog, "proj");
+	tri_num_loc = glGetUniformLocation(prog, "tri_num");
+	viewport_size_loc = glGetUniformLocation(prog, "viewport_size");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	glGenBuffers(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, ARRAY_SIZE(vertex_data[0].pos_within_tri),
+			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) offsetof(vertex_attributes,
+						pos_within_tri));
+	glEnableVertexAttribArray(1);
+	glVertexAttribPointer(1, ARRAY_SIZE(vertex_data[0].barycentric_coords),
+			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) offsetof(vertex_attributes,
+						barycentric_coords));
+}
+
+
+void
+InterpolationTestPattern::draw(const float (*proj)[4])
+{
+	glUseProgram(prog);
+
+	/* Depending what the fragment shader does, it's possible that
+	 * viewport_size might get optimized away.  Only set it if it
+	 * didn't.
+	 */
+	if (viewport_size_loc != -1) {
+		GLint viewport_dims[4];
+		glGetIntegerv(GL_VIEWPORT, viewport_dims);
+		glUniform2i(viewport_size_loc, viewport_dims[2], viewport_dims[3]);
+	}
+
+	Triangles::draw(proj);
+}
+
+
+void Lines::compile()
+{
+	/* Line coords within (-1,-1) to (1,1) rect */
+	static const float pos_line[][2] = {
+		{ -0.8, -0.5 },
+		{  0.8, -0.5 }
+	};
+
+	/* Number of line instances across (and down) */
+	int lines_across = 4;
+
+	/* Total number of lines drawn */
+	num_lines = lines_across * lines_across;
+
+	/* Amount each line should be rotated compared to prev */
+	float rotation_delta = M_PI * 2.0 / num_lines;
+
+	/* Scaling factor uniformly applied to line coords */
+	float line_scale = 0.8 / lines_across;
+
+	/* Final scaling factor */
+	float final_scale = 0.95;
+
+	static const char *vert =
+		"#version 120\n"
+		"attribute vec2 pos_line;\n"
+		"uniform float line_scale;\n"
+		"uniform float rotation_delta;\n"
+		"uniform int lines_across;\n"
+		"uniform float final_scale;\n"
+		"uniform mat4 proj;\n"
+		"uniform int line_num;\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"  vec2 pos = line_scale * pos_line;\n"
+		"  float rotation = rotation_delta * line_num;\n"
+		"  pos = mat2(cos(rotation), sin(rotation),\n"
+		"             -sin(rotation), cos(rotation)) * pos;\n"
+		"  int i = int(mod(float(line_num), float(lines_across)));\n"
+		"  int j = lines_across - 1 - line_num / lines_across;\n"
+		"  pos += (vec2(i, j) * 2.0 + 1.0) / lines_across - 1.0;\n"
+		"  pos *= final_scale;\n"
+		"  gl_Position = proj * vec4(pos, 0.0, 1.0);\n"
+		"}\n";
+
+	static const char *frag =
+		"#version 120\n"
+		"void main()\n"
+		"{\n"
+		"  gl_FragColor = vec4(1.0);\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	glAttachShader(prog, vs);
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	glAttachShader(prog, fs);
+	glBindAttribLocation(prog, 0, "pos_line");
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	glUniform1f(glGetUniformLocation(prog, "line_scale"), line_scale);
+	glUniform1f(glGetUniformLocation(prog, "rotation_delta"),
+		    rotation_delta);
+	glUniform1i(glGetUniformLocation(prog, "lines_across"), lines_across);
+	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
+	proj_loc = glGetUniformLocation(prog, "proj");
+	line_num_loc = glGetUniformLocation(prog, "line_num");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	glGenBuffers(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(pos_line), pos_line,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, ARRAY_SIZE(pos_line[0]), GL_FLOAT,
+			      GL_FALSE, sizeof(pos_line[0]), (void *) 0);
+}
+
+void Lines::draw(const float (*proj)[4])
+{
+	glClear(GL_COLOR_BUFFER_BIT);
+	glUseProgram(prog);
+	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
+	glBindVertexArray(vao);
+	for (int line_num = 0; line_num < num_lines; ++line_num) {
+		/* Draws with line width = 0.25, 0.75, 1.25,
+		 * 1.75, 2.25, 2.75, 3.25, 3.75
+		 */
+		glLineWidth((1 + 2 * line_num) / 4.0);
+		glUniform1i(line_num_loc, line_num);
+		glDrawArrays(GL_LINES, 0, 2);
+	}
+}
+
+void Points::compile()
+{
+	/* Point coords within (-1,-1) to (1,1) rect */
+	static const float pos_point[2] = { -0.5, -0.5 };
+
+	/* Number of point instances across (and down) */
+	int points_across = 4;
+
+	/* Total number of points drawn */
+	num_points = points_across * points_across;
+
+	/* Scaling factor uniformly applied to point coords */
+	float point_scale = 0.8 / points_across;
+
+	/* Final scaling factor */
+	float final_scale = 0.95;
+
+	static const char *vert =
+		"#version 120\n"
+		"attribute vec2 pos_point;\n"
+		"uniform float point_scale;\n"
+		"uniform int points_across;\n"
+		"uniform float final_scale;\n"
+		"uniform mat4 proj;\n"
+		"uniform int point_num;\n"
+		"uniform float depth;\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"  vec2 pos = point_scale * pos_point;\n"
+		"  int i = int(mod(float(point_num), float(points_across)));\n"
+		"  int j = points_across - 1 - point_num / points_across;\n"
+		"  pos += (vec2(i, j) * 2.0 + 1.0) / points_across - 1.0;\n"
+		"  pos *= final_scale;\n"
+		"  gl_Position = proj * vec4(pos, depth, 1.0);\n"
+		"}\n";
+
+	static const char *frag =
+		"#version 120\n"
+		"void main()\n"
+		"{\n"
+		"  gl_FragColor = vec4(1.0);\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	glAttachShader(prog, vs);
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	glAttachShader(prog, fs);
+	glBindAttribLocation(prog, 0, "pos_point");
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	glUniform1f(glGetUniformLocation(prog, "point_scale"), point_scale);
+	glUniform1i(glGetUniformLocation(prog, "points_across"), points_across);
+	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
+	proj_loc = glGetUniformLocation(prog, "proj");
+	point_num_loc = glGetUniformLocation(prog, "point_num");
+	depth_loc = glGetUniformLocation(prog, "depth");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	glGenBuffers(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(pos_point), pos_point,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, ARRAY_SIZE(pos_point), GL_FLOAT,
+			      GL_FALSE, 0, (void *) 0);
+}
+
+void Points::draw(const float (*proj)[4])
+{
+	glClear(GL_COLOR_BUFFER_BIT);
+	glUseProgram(prog);
+	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
+	glBindVertexArray(vao);
+	glUniform1f(depth_loc, 0.0);
+	for (int point_num = 0; point_num < num_points; ++point_num) {
+		glPointSize((1.0 + 4 * point_num) / 4.0);
+		glUniform1i(point_num_loc, point_num);
+		glDrawArrays(GL_POINTS, 0, 1);
+	}
+}
+
+Sunburst::Sunburst()
+	: out_type(GL_UNSIGNED_NORMALIZED),
+	  compute_depth(false),
+	  prog(0),
+	  rotation_loc(0),
+	  vert_depth_loc(0),
+	  frag_depth_loc(0),
+	  proj_loc(0),
+	  draw_colors_loc(0),
+	  vao(0),
+	  num_tris(0),
+	  vertex_buf(0)
+{
+}
+
+
+/**
+ * Determine the GLSL type that should be used for rendering, based on
+ * out_type.
+ */
+const char *
+Sunburst::get_out_type_glsl() const
+{
+	switch(out_type) {
+	case GL_INT:
+		return "ivec4";
+	case GL_UNSIGNED_INT:
+		return "uvec4";
+	case GL_UNSIGNED_NORMALIZED:
+	case GL_FLOAT:
+		return "vec4";
+	default:
+		printf("Unrecognized out_type: %s\n",
+		       piglit_get_gl_enum_name(out_type));
+		piglit_report_result(PIGLIT_FAIL);
+		return "UNKNOWN";
+	}
+}
+
+
+void Sunburst::compile()
+{
+	static struct vertex_attributes {
+		float pos_within_tri[2];
+		float barycentric_coords[3];
+	} vertex_data[] = {
+		{ { -0.3, -0.8 }, { 1, 0, 0 } },
+		{ {  0.0,  1.0 }, { 0, 1, 0 } },
+		{ {  0.3, -0.8 }, { 0, 0, 1 } }
+	};
+        bool need_glsl130 = out_type == GL_INT || out_type == GL_UNSIGNED_INT;
+
+	if (need_glsl130) {
+		piglit_require_gl_version(30);
+	}
+
+	/* Total number of triangles drawn */
+	num_tris = 7;
+
+	static const char *vert_template =
+		"#version %s\n"
+		"attribute vec2 pos_within_tri;\n"
+		"attribute vec3 in_barycentric_coords;\n"
+		"varying vec3 barycentric_coords;\n"
+		"uniform float rotation;\n"
+		"uniform float vert_depth;\n"
+		"uniform mat4 proj;\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"  vec2 pos = pos_within_tri;\n"
+		"  pos = mat2(cos(rotation), sin(rotation),\n"
+		"             -sin(rotation), cos(rotation)) * pos;\n"
+		"  gl_Position = proj * vec4(pos, vert_depth, 1.0);\n"
+		"  barycentric_coords = in_barycentric_coords;\n"
+		"}\n";
+
+	static const char *frag_template =
+		"#version %s\n"
+		"#define OUT_TYPE %s\n"
+		"#define COMPUTE_DEPTH %s\n"
+		"uniform float frag_depth;\n"
+		"varying vec3 barycentric_coords;\n"
+		"uniform mat3x4 draw_colors;\n"
+		"#if __VERSION__ == 130\n"
+		"  out OUT_TYPE frag_out;\n"
+		"#endif\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"#if __VERSION__ == 130\n"
+		"  frag_out = OUT_TYPE(draw_colors * barycentric_coords);\n"
+		"#else\n"
+		"  gl_FragColor = draw_colors * barycentric_coords;\n"
+		"#endif\n"
+		"#if COMPUTE_DEPTH\n"
+		"  gl_FragDepth = (frag_depth + 1.0) / 2.0;\n"
+		"#endif\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	unsigned vert_alloc_len =
+		strlen(vert_template) + 4;
+	char *vert = (char *) malloc(vert_alloc_len);
+	sprintf(vert, vert_template, need_glsl130 ? "130" : "120");
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	free(vert);
+	glAttachShader(prog, vs);
+
+	const char *out_type_glsl = get_out_type_glsl();
+	unsigned frag_alloc_len =
+		strlen(frag_template) + strlen(out_type_glsl) + 4;
+	char *frag = (char *) malloc(frag_alloc_len);
+	sprintf(frag, frag_template, need_glsl130 ? "130" : "120",
+		out_type_glsl,
+		compute_depth ? "1" : "0");
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	free(frag);
+	glAttachShader(prog, fs);
+
+	glBindAttribLocation(prog, 0, "pos_within_tri");
+	glBindAttribLocation(prog, 1, "in_barycentric_coords");
+	if (need_glsl130) {
+		glBindFragDataLocation(prog, 0, "frag_out");
+	}
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	rotation_loc = glGetUniformLocation(prog, "rotation");
+	vert_depth_loc = glGetUniformLocation(prog, "vert_depth");
+	frag_depth_loc = glGetUniformLocation(prog, "frag_depth");
+	glUniform1f(vert_depth_loc, 0.0);
+	glUniform1f(frag_depth_loc, 0.0);
+	proj_loc = glGetUniformLocation(prog, "proj");
+	draw_colors_loc = glGetUniformLocation(prog, "draw_colors");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	glGenBuffers(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, ARRAY_SIZE(vertex_data[0].pos_within_tri),
+			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) 0);
+	glEnableVertexAttribArray(1);
+	glVertexAttribPointer(1, ARRAY_SIZE(vertex_data[0].barycentric_coords),
+			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) offsetof(vertex_attributes,
+						barycentric_coords));
+}
+
+
+ColorGradientSunburst::ColorGradientSunburst(GLenum out_type)
+{
+	this->out_type = out_type;
+}
+
+
+/**
+ * Draw the color gradient sunburst, but instead of using color
+ * components that range from 0.0 to 1.0, apply the given scaling
+ * factor and offset to each color component.
+ *
+ * The offset is also applied when clearing the color buffer.
+ */
+void
+ColorGradientSunburst::draw_with_scale_and_offset(const float (*proj)[4],
+						  float scale, float offset)
+{
+	switch (out_type) {
+	case GL_INT: {
+		int clear_color[4] = { offset, offset, offset, offset };
+		glClearBufferiv(GL_COLOR, 0, clear_color);
+		break;
+	}
+	case GL_UNSIGNED_INT: {
+		unsigned clear_color[4] = { offset, offset, offset, offset };
+		glClearBufferuiv(GL_COLOR, 0, clear_color);
+		break;
+	}
+	case GL_UNSIGNED_NORMALIZED:
+	case GL_FLOAT: {
+		glClearColor(offset, offset, offset, offset);
+		glClear(GL_COLOR_BUFFER_BIT);
+		break;
+	}
+	default:
+		printf("Unrecognized out_type: %s\n",
+		       piglit_get_gl_enum_name(out_type));
+		piglit_report_result(PIGLIT_FAIL);
+		break;
+	}
+
+	glUseProgram(prog);
+	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
+	float draw_colors[3][4] =
+		{ { 1, 0, 0, 1.0 }, { 0, 1, 0, 0.5 }, { 0, 0, 1, 1.0 } };
+	for (int i = 0; i < 3; ++i) {
+		for (int j = 0; j < 4; ++j) {
+			draw_colors[i][j] = scale * draw_colors[i][j] + offset;
+		}
+	}
+	glUniformMatrix3x4fv(draw_colors_loc, 1, GL_FALSE,
+			     &draw_colors[0][0]);
+	glBindVertexArray(vao);
+	for (int i = 0; i < num_tris; ++i) {
+		glUniform1f(rotation_loc, M_PI * 2.0 * i / num_tris);
+		glDrawArrays(GL_TRIANGLES, 0, 3);
+	}
+}
+
+
+void
+ColorGradientSunburst::draw(const float (*proj)[4])
+{
+	draw_with_scale_and_offset(proj, 1.0, 0.0);
+}
+
+
+void
+StencilSunburst::draw(const float (*proj)[4])
+{
+	glEnable(GL_STENCIL_TEST);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+	glUseProgram(prog);
+	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
+	glBindVertexArray(vao);
+	for (int i = 0; i < num_tris; ++i) {
+		glStencilFunc(GL_ALWAYS, i+1, 0xff);
+		glUniform1f(rotation_loc, M_PI * 2.0 * i / num_tris);
+		glDrawArrays(GL_TRIANGLES, 0, 3);
+	}
+
+	glDisable(GL_STENCIL_TEST);
+}
+
+
+DepthSunburst::DepthSunburst(bool compute_depth)
+{
+	this->compute_depth = compute_depth;
+}
+
+
+void
+DepthSunburst::draw(const float (*proj)[4])
+{
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LESS);
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	glUseProgram(prog);
+	glUniformMatrix4fv(proj_loc, 1, GL_TRUE, &proj[0][0]);
+	glBindVertexArray(vao);
+	for (int i = 0; i < num_tris; ++i) {
+		/* Draw triangles in a haphazard order so we can
+		 * verify that depth comparisons sort them out
+		 * properly.
+		 */
+		int triangle_to_draw = (i * 3) % num_tris;
+
+		/* Note: with num_tris == 7, this causes us to draw
+		 * triangles at depths of 3/4, 1/2, -1/4, 0, 1/4, 1/2,
+		 * and 3/4.
+		 */
+		glUniform1f(compute_depth ? frag_depth_loc : vert_depth_loc,
+			    float(num_tris - triangle_to_draw * 2 - 1)
+			    / (num_tris + 1));
+
+		glUniform1f(rotation_loc,
+			    M_PI * 2.0 * triangle_to_draw / num_tris);
+		glDrawArrays(GL_TRIANGLES, 0, 3);
+	}
+
+	glDisable(GL_DEPTH_TEST);
+}
+
+
+void
+ManifestStencil::compile()
+{
+	static const char *vert =
+		"#version 120\n"
+		"attribute vec2 pos;\n"
+		"void main()\n"
+		"{\n"
+		"  gl_Position = vec4(pos, 0.0, 1.0);\n"
+		"}\n";
+
+	static const char *frag =
+		"#version 120\n"
+		"uniform vec4 color;\n"
+		"void main()\n"
+		"{\n"
+		"  gl_FragColor = color;\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	glAttachShader(prog, vs);
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	glAttachShader(prog, fs);
+	glBindAttribLocation(prog, 0, "pos");
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	color_loc = glGetUniformLocation(prog, "color");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	float vertex_data[4][2] = {
+		{ -1, -1 },
+		{ -1,  1 },
+		{  1,  1 },
+		{  1, -1 }
+	};
+	glGenVertexArrays(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) 0);
+
+	/* Set up element input buffer to tesselate a quad into
+	 * triangles
+	 */
+	unsigned int indices[6] = { 0, 1, 2, 0, 2, 3 };
+	GLuint element_buf;
+	glGenBuffers(1, &element_buf);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buf);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
+		     GL_STATIC_DRAW);
+}
+
+void
+ManifestStencil::run()
+{
+	static float colors[8][4] = {
+		{ 0.0, 0.0, 0.0, 1.0 },
+		{ 0.0, 0.0, 1.0, 1.0 },
+		{ 0.0, 1.0, 0.0, 1.0 },
+		{ 0.0, 1.0, 1.0, 1.0 },
+		{ 1.0, 0.0, 0.0, 1.0 },
+		{ 1.0, 0.0, 1.0, 1.0 },
+		{ 1.0, 1.0, 0.0, 1.0 },
+		{ 1.0, 1.0, 1.0, 1.0 }
+	};
+
+	glUseProgram(prog);
+	glBindVertexArray(vao);
+
+	glEnable(GL_STENCIL_TEST);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+	/* Clear the color buffer to 0, in case the stencil buffer
+	 * contains any values outside the range 0..7
+	 */
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	for (int i = 0; i < 8; ++i) {
+		glStencilFunc(GL_EQUAL, i, 0xff);
+		glUniform4fv(color_loc, 1, colors[i]);
+		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void *) 0);
+	}
+
+	glDisable(GL_STENCIL_TEST);
+}
+
+void
+ManifestDepth::compile()
+{
+	static const char *vert =
+		"#version 120\n"
+		"attribute vec2 pos;\n"
+		"uniform float depth;\n"
+		"void main()\n"
+		"{\n"
+		"  gl_Position = vec4(pos, depth, 1.0);\n"
+		"}\n";
+
+	static const char *frag =
+		"#version 120\n"
+		"uniform vec4 color;\n"
+		"void main()\n"
+		"{\n"
+		"  gl_FragColor = color;\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	glAttachShader(prog, vs);
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	glAttachShader(prog, fs);
+	glBindAttribLocation(prog, 0, "pos");
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	color_loc = glGetUniformLocation(prog, "color");
+	depth_loc = glGetUniformLocation(prog, "depth");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	float vertex_data[4][2] = {
+		{ -1, -1 },
+		{ -1,  1 },
+		{  1,  1 },
+		{  1, -1 }
+	};
+	glGenVertexArrays(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) 0);
+
+	/* Set up element input buffer to tesselate a quad into
+	 * triangles
+	 */
+	unsigned int indices[6] = { 0, 1, 2, 0, 2, 3 };
+	GLuint element_buf;
+	glGenBuffers(1, &element_buf);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buf);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
+		     GL_STATIC_DRAW);
+}
+
+void
+ManifestDepth::run()
+{
+	static float colors[8][4] = {
+		{ 0.0, 0.0, 0.0, 1.0 },
+		{ 0.0, 0.0, 1.0, 1.0 },
+		{ 0.0, 1.0, 0.0, 1.0 },
+		{ 0.0, 1.0, 1.0, 1.0 },
+		{ 1.0, 0.0, 0.0, 1.0 },
+		{ 1.0, 0.0, 1.0, 1.0 },
+		{ 1.0, 1.0, 0.0, 1.0 },
+		{ 1.0, 1.0, 1.0, 1.0 }
+	};
+
+	glUseProgram(prog);
+	glBindVertexArray(vao);
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LESS);
+	glEnable(GL_STENCIL_TEST);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+	glStencilFunc(GL_EQUAL, 0, 0xff);
+
+	/* Clear the stencil buffer to 0, leaving depth and color
+	 * buffers unchanged.
+	 */
+	glClear(GL_STENCIL_BUFFER_BIT);
+
+	for (int i = 0; i < 8; ++i) {
+		glUniform4fv(color_loc, 1, colors[i]);
+		glUniform1f(depth_loc, float(7 - 2*i)/8);
+		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void *) 0);
+	}
+
+	glDisable(GL_STENCIL_TEST);
+	glDisable(GL_DEPTH_TEST);
+}
diff --git a/tests/util/piglit-test-pattern.h b/tests/util/piglit-test-pattern.h
new file mode 100644
index 0000000..026c5a1
--- /dev/null
+++ b/tests/util/piglit-test-pattern.h
@@ -0,0 +1,322 @@
+/* Copyright © 2013 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 piglit-util-test-pattern.h
+ * This file declares classes and functions which can be utilized to draw
+ * test patterns in to color, depth or stencil buffers.
+ */
+
+#include "piglit-util-gl-common.h"
+#include "math.h"
+
+/**
+ * There are two programs used to "manifest" an auxiliary buffer,
+ * turning it into visible colors: one for manifesting the stencil
+ * buffer, and one for manifesting the depth buffer.  This is the base
+ * class that they both derive from.
+ */
+class ManifestProgram
+{
+public:
+	virtual void compile() = 0;
+	virtual void run() = 0;
+};
+
+/**
+ * Program we use to manifest the stencil buffer.
+ *
+ * This program operates by repeatedly drawing over the entire buffer
+ * using the stencil function "EQUAL", and a different color each
+ * time.  This causes stencil values from 0 to 7 to manifest as colors
+ * (black, blue, green, cyan, red, magenta, yellow, white).
+ */
+class ManifestStencil : public ManifestProgram
+{
+public:
+	virtual void compile();
+	virtual void run();
+
+private:
+	GLint prog;
+	GLint color_loc;
+	GLuint vertex_buf;
+	GLuint vao;
+};
+
+/**
+ * Program we use to manifest the depth buffer.
+ *
+ * This program operates by repeatedly drawing over the entire buffer
+ * at decreasing depth values with depth test enabled; the stencil
+ * function is configured to "EQUAL" with a stencil op of "INCR", so
+ * that after a sample passes the depth test, its stencil value will
+ * be incremented and it will fail the stencil test on later draws.
+ * As a result, depth values from back to front will manifest as
+ * colors (black, blue, green, cyan, red, magenta, yellow, white).
+ */
+class ManifestDepth : public ManifestProgram
+{
+public:
+	virtual void compile();
+	virtual void run();
+
+private:
+	GLint prog;
+	GLint color_loc;
+	GLint depth_loc;
+	GLuint vertex_buf;
+	GLuint vao;
+};
+
+/**
+ * There are three programs used to draw a test pattern, depending on
+ * whether we are testing the color buffer, the depth buffer, or the
+ * stencil buffer.  This is the base class that they all derive from.
+ */
+class TestPattern
+{
+public:
+	virtual void compile() = 0;
+
+	/**
+	 * Draw the test pattern, applying the given projection matrix
+	 * to vertex coordinates.  The projection matrix is in
+	 * row-major order.
+	 *
+	 * If no projection transformation is needed, pass
+	 * TestPattern::no_projection for \c proj.
+	 */
+	virtual void draw(const float (*proj)[4]) = 0;
+
+	static const float no_projection[4][4];
+};
+
+/**
+ * Program we use to draw a test pattern into the color buffer.
+ *
+ * This program draws a grid of small disjoint triangles, each rotated
+ * at a different angle.  This ensures that the image will have a
+ * large number of edges at different angles, so that we'll thoroughly
+ * exercise antialiasing.
+ */
+class Triangles : public TestPattern
+{
+public:
+	virtual void compile();
+	virtual void draw(const float (*proj)[4]);
+
+protected:
+	GLint prog;
+	GLuint vertex_buf;
+	GLuint vao;
+	GLint proj_loc;
+	GLint tri_num_loc;
+	int num_tris;
+};
+
+
+/**
+ * Program we use to test that interpolation works properly.
+ *
+ * This program draws the same sequence of small triangles as the
+ * Triangles program, but it's capable of coloring the triangles in
+ * various ways based on the fragment program provided to the
+ * constructor.
+ *
+ * The fragment program has access to the following variables:
+ *
+ * - in vec3 barycentric_coords: barycentric coordinates of the
+ *   triangle being drawn, normally interpolated.
+ *
+ * - centroid in vec3 barycentric_coords_centroid: same as
+ *   barycentric_coords, but centroid interpolated.
+ *
+ * - in vec2 pixel_pos: pixel coordinate ((0,0) to (viewport_width,
+ *   viewport_height)), normally interpolated.
+ *
+ * - centroid in vec2 pixel_pos_centroid: same as pixel_pos, but
+ *   centroid interpolated.
+ */
+class InterpolationTestPattern : public Triangles
+{
+public:
+	explicit InterpolationTestPattern(const char *frag);
+	virtual void compile();
+	virtual void draw(const float (*proj)[4]);
+
+private:
+	const char *frag;
+	GLint viewport_size_loc;
+};
+
+
+/**
+ * Program we use to draw a test pattern into the color buffer.
+ *
+ * This program draws a sequence of points with varied sizes. This ensures
+ * antialiasing works well with all point sizes.
+ */
+class Points : public TestPattern
+{
+public:
+	virtual void compile();
+	virtual void draw(const float (*proj)[4]);
+
+private:
+	GLint prog;
+	GLuint vao;
+	GLint proj_loc;
+	GLint depth_loc;
+	GLint point_num_loc;
+	GLuint vertex_buf;
+	int num_points;
+};
+
+/**
+ * Program we use to draw a test pattern into the color buffer.
+ *
+ * This program draws a sequence of lines with varied width. This ensures
+ * antialiasing works well with all line widths.
+ */
+class Lines : public TestPattern
+{
+public:
+	virtual void compile();
+	virtual void draw(const float (*proj)[4]);
+
+private:
+	GLint prog;
+	GLuint vao;
+	GLint proj_loc;
+	GLint line_num_loc;
+	GLuint vertex_buf;
+	int num_lines;
+};
+
+/**
+ * Program we use to draw a test pattern into the depth and stencil
+ * buffers.
+ *
+ * This program draws a "sunburst" pattern consisting of 7 overlapping
+ * triangles, each at a different angle.  This ensures that the
+ * triangles overlap in a complex way, with the edges between them
+ * covering a a large number of different angles, so that we'll
+ * thoroughly exercise antialiasing.
+ *
+ * This program is further specialized into depth and stencil variants.
+ */
+class Sunburst : public TestPattern
+{
+public:
+	Sunburst();
+
+	virtual void compile();
+
+	/**
+	 * Type of color buffer being rendered into.  Should be one of
+	 * the following enum values: GL_FLOAT,
+	 * GL_UNSIGNED_NORMALIZED, GL_UNSIGNED_INT, or GL_INT.
+	 *
+	 * Defaults to GL_UNSIGNED_NORMALIZED.
+	 */
+	GLenum out_type;
+
+	/**
+	 * Whether or not the fragment shader should output a depth
+	 * value.
+	 *
+	 * Defaults to false.
+	 */
+	bool compute_depth;
+
+protected:
+	GLint prog;
+	GLint rotation_loc;
+	GLint vert_depth_loc;
+	GLint frag_depth_loc;
+	GLint proj_loc;
+	GLint draw_colors_loc;
+	GLuint vao;
+	int num_tris;
+
+private:
+	const char *get_out_type_glsl() const;
+
+	GLuint vertex_buf;
+};
+
+/**
+ * Program that draws a test pattern into the color buffer.
+ *
+ * This program draws triangles using a variety of colors and
+ * gradients.
+ *
+ * This program is capable of drawing to floating point, integer, and
+ * unsigned integer framebuffers, controlled by the out_type
+ * constructor parameter, which should be GL_FLOAT,
+ * GL_UNSIGNED_NORMALIZED, GL_UNSIGNED_INT, or GL_INT.
+ */
+class ColorGradientSunburst : public Sunburst
+{
+public:
+	explicit ColorGradientSunburst(GLenum out_type);
+
+	virtual void draw(const float (*proj)[4]);
+
+	void draw_with_scale_and_offset(const float (*proj)[4],
+					float scale, float offset);
+};
+
+/**
+ * Program we use to draw a test pattern into the stencil buffer.
+ *
+ * The triangles in this sunburst are drawn back-to-front, using no
+ * depth testing.  Each triangle is drawn using a different stencil
+ * value.
+ */
+class StencilSunburst : public Sunburst
+{
+public:
+	virtual void draw(const float (*proj)[4]);
+};
+
+/**
+ * Program we use to draw a test pattern into the depth buffer.
+ *
+ * The triangles in this sunburst are drawn at a series of different
+ * depth values, with depth testing enabled.  They are drawn in an
+ * arbitrary non-consecutive order, to verify that depth testing
+ * properly sorts the surfaces into front-to-back order.
+ *
+ * If the constructor parameter compute_depth is true, the depth value
+ * is determined using a fragment shader output.  If it is false, it
+ * is determined by the z value of the vertex shader gl_Position
+ * output.
+ */
+class DepthSunburst : public Sunburst
+{
+public:
+	explicit DepthSunburst(bool compute_depth = false);
+
+	virtual void draw(const float (*proj)[4]);
+};
-- 
1.8.1.4



More information about the Piglit mailing list