BPTC float variants test case.

Submitted by Glenn Kennard on July 26, 2014, 3:12 p.m.

Details

Message ID 1406387556-5803-1-git-send-email-glenn.kennard@gmail.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Glenn Kennard July 26, 2014, 3:12 p.m.
Signed-off-by: Glenn Kennard <glenn.kennard@gmail.com>
---
Mostly intended to test the hardware driver back ends rather than
the BPTC encoder.

 tests/all.py                      |  14 +-
 tests/texturing/CMakeLists.gl.txt |   1 +
 tests/texturing/bptc-float.c      | 363 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 374 insertions(+), 4 deletions(-)
 create mode 100644 tests/texturing/bptc-float.c

Patch hide | download patch | download mbox

diff --git a/tests/all.py b/tests/all.py
index a1f652c..a45049a 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -2281,10 +2281,6 @@  add_texwrap_format_tests(arb_texture_compression, 'GL_ARB_texture_compression')
 arb_texture_compression['GL_TEXTURE_INTERNAL_FORMAT query'] = concurrent_test('arb_texture_compression-internal-format-query')
 arb_texture_compression['unknown formats'] = concurrent_test('arb_texture_compression-invalid-formats unknown')
 
-arb_texture_compression_bptc = {}
-spec['ARB_texture_compression_bptc'] = arb_texture_compression_bptc
-arb_texture_compression_bptc['invalid formats'] = concurrent_test('arb_texture_compression-invalid-formats bptc')
-
 ext_vertex_array_bgra = {}
 spec['EXT_vertex_array_bgra'] = ext_vertex_array_bgra
 add_plain_test(ext_vertex_array_bgra, 'bgra-sec-color-pointer')
@@ -2841,6 +2837,16 @@  add_fbo_generatemipmap_extension(ati_texture_compression_3dc, 'GL_ATI_texture_co
 add_texwrap_format_tests(ati_texture_compression_3dc, 'GL_ATI_texture_compression_3dc')
 ati_texture_compression_3dc['invalid formats'] = concurrent_test('arb_texture_compression-invalid-formats 3dc')
 
+arb_texture_compression_bptc = {}
+spec['ARB_texture_compression_bptc'] = arb_texture_compression_bptc
+arb_texture_compression_bptc['invalid formats'] = concurrent_test('arb_texture_compression-invalid-formats bptc')
+add_concurrent_test(arb_texture_compression_bptc, 'bptc-float signed dc')
+add_concurrent_test(arb_texture_compression_bptc, 'bptc-float signed fastest')
+add_concurrent_test(arb_texture_compression_bptc, 'bptc-float signed nicest')
+add_concurrent_test(arb_texture_compression_bptc, 'bptc-float unsigned dc')
+add_concurrent_test(arb_texture_compression_bptc, 'bptc-float unsigned fastest')
+add_concurrent_test(arb_texture_compression_bptc, 'bptc-float unsigned nicest')
+
 ext_packed_float = {}
 spec['EXT_packed_float'] = ext_packed_float
 add_fbo_formats_tests('spec/EXT_packed_float', 'GL_EXT_packed_float')
diff --git a/tests/texturing/CMakeLists.gl.txt b/tests/texturing/CMakeLists.gl.txt
index b121163..b9c77af 100644
--- a/tests/texturing/CMakeLists.gl.txt
+++ b/tests/texturing/CMakeLists.gl.txt
@@ -13,6 +13,7 @@  link_libraries (
 piglit_add_executable (1-1-linear-texture 1-1-linear-texture.c)
 piglit_add_executable (array-depth-roundtrip array-depth-roundtrip.c)
 piglit_add_executable (array-texture array-texture.c)
+piglit_add_executable (bptc-float bptc-float.c)
 piglit_add_executable (compressedteximage compressedteximage.c)
 piglit_add_executable (copytexsubimage copytexsubimage.c)
 piglit_add_executable (copyteximage copyteximage.c)
diff --git a/tests/texturing/bptc-float.c b/tests/texturing/bptc-float.c
new file mode 100644
index 0000000..a08b3f4
--- /dev/null
+++ b/tests/texturing/bptc-float.c
@@ -0,0 +1,363 @@ 
+/** @file bptc-float.c
+ *
+ * Test that passing float data and compressing to BPTC float and unsigned float
+ * formats produce expected results both for rendering and getting float data back from
+ * texture.
+ *
+ * Also test that getting the compressed data and passing back to the driver renders bit
+ * for bit identical results to those produced by the on-line compressed texture.
+ *
+ * This is just a basic sanity check, not a compressor accuracy test.
+ */
+
+#include "piglit-util-gl.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+	config.supports_gl_compat_version = 30;
+
+	config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+#define BLOCK_SIZE 4
+#define IMAGE_WIDTH (4 * BLOCK_SIZE)
+#define IMAGE_HEIGHT (4 * BLOCK_SIZE)
+
+static GLenum compression_hint = GL_DONT_CARE;
+static bool signed_format = false;
+
+
+// 5 mantissa bits ie 32 values per exponent range, -2 bits for roundoff/dithering errors
+// -> 1/8 = 0.125.
+//static const float tolerance = 0.125f;
+static const float tolerance = 0.25f;
+
+// TODO: color code the blocks, right now its just a checkerboard
+// Each block is a solid color, to avoid compressor artifacts
+// the float values are chosen to easily be represented exactly in BPTC
+static void
+make_float_image(bool is_signed, float *out)
+{
+	int x, y;
+	for (y = 0; y < IMAGE_HEIGHT; y++) {
+		for (x = 0; x < IMAGE_WIDTH; x++) {
+			float *pixel = out + (y * IMAGE_WIDTH + x) * 3;
+			int block_x = x / BLOCK_SIZE;
+			int block_y = y / BLOCK_SIZE;
+			float v = exp((~block_x ^ block_y) & 7);
+			pixel[0] = (float)x / IMAGE_WIDTH;
+			pixel[1] = is_signed ? -v : v;
+			pixel[2] = (float)y / IMAGE_HEIGHT;
+		}
+	}
+}
+
+
+static GLuint
+make_tex(float *image_ref, bool is_signed, GLenum compression_hint)
+{
+	GLuint tex;
+
+	make_float_image(is_signed, image_ref);
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_2D, tex);
+
+	glHint(GL_TEXTURE_COMPRESSION_HINT, compression_hint);
+
+	glTexImage2D(GL_TEXTURE_2D, 0,
+				 is_signed ? GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT : GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
+				 IMAGE_WIDTH, IMAGE_HEIGHT, 0, GL_RGB, GL_FLOAT, image_ref),
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	return tex;
+}
+
+
+static int floatdiff(float a, float b)
+{
+	if (fabs(a - b) < tolerance) // accept larger relative errors close to zero
+		return false;
+	if (a == b)
+		return false;
+	if (b == 0)
+		return true;
+	return fabsf((b - a) / b) > tolerance;
+}
+
+
+static bool
+compare_block_results(const float *expected,
+					  const float *observed)
+{
+	int y, x;
+	int rowpad = IMAGE_WIDTH * 3 - 3 * BLOCK_SIZE;
+
+	for (y = 0; y < BLOCK_SIZE; y++) {
+		for (x = 0; x < BLOCK_SIZE; x++) {
+			if (floatdiff(expected[0], observed[0]) ||
+				floatdiff(expected[1], observed[1]) ||
+				floatdiff(expected[2], observed[2])) {
+				printf("Unexpected color at %d,%d:\n"
+					   "\texpected %g,%g,%g\n"
+					   "\tobserved %g,%g,%g\n",
+					   x, y,
+					   expected[0], expected[1], expected[2],
+					   observed[0], observed[1], observed[2]);
+				return false;
+			}
+
+			expected += 3;
+			observed += 3;
+		}
+
+		observed += rowpad;
+		expected += rowpad;
+	}
+
+	return true;
+}
+
+
+static bool
+compare_precompressed(GLuint online_tex, const float *online_ref, bool is_signed)
+{
+	uint8_t compressed_data[(IMAGE_WIDTH/BLOCK_SIZE) * (IMAGE_HEIGHT/BLOCK_SIZE) * 16] = {0};
+	float precompressed_image[IMAGE_WIDTH * IMAGE_HEIGHT * 3] = {0};
+	bool pass = true;
+	GLuint tex;
+	int n;
+
+	glBindTexture(GL_TEXTURE_2D, online_tex);
+
+	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &n);
+	if (n != sizeof(compressed_data)) {
+		printf("GL_TEXTURE_COMPRESSED_IMAGE_SIZE returning incorrect size %d, expected %zd\n",
+			   n, sizeof(compressed_data));
+		return false;
+	}
+	glGetCompressedTexImage(GL_TEXTURE_2D, 0, compressed_data);
+	glBindTexture(GL_TEXTURE_2D, 0);
+
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	// Pre-compressed data should bit bit identical rendering results
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_2D, tex);
+
+	glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+				 is_signed ? GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT : GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
+				 IMAGE_WIDTH, IMAGE_HEIGHT, 0, sizeof(compressed_data), compressed_data),
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	// draw pre-compressed texture
+	glEnable(GL_TEXTURE_2D);
+	piglit_draw_rect_tex(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
+						 0.0f, 0.0f, 1.0f, 1.0f);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glDeleteTextures(1, &tex);
+
+	glReadPixels(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
+				 GL_RGB, GL_FLOAT, precompressed_image);
+
+	if (memcmp(online_ref, precompressed_image, sizeof(precompressed_image))) {
+		pass = false;
+	}
+
+	printf("render of online compressed texture and precompressed texture produces identical results: %s\n",
+		   pass ? "pass" : "fail");
+
+	return pass;
+}
+
+
+static bool
+render_texture(bool is_signed,
+			   GLenum compress_hint,
+			   float *image_ref,
+			   float *render_data,
+			   float *get_data)
+{
+	GLuint tex;
+	bool pass;
+
+	tex = make_tex(image_ref, is_signed, compress_hint);
+
+	memset(render_data, 0xff, IMAGE_WIDTH * IMAGE_HEIGHT * 3);
+	memset(get_data, 0xff, IMAGE_WIDTH * IMAGE_HEIGHT * 3);
+
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glBindTexture(GL_TEXTURE_2D, tex);
+	glEnable(GL_TEXTURE_2D);
+
+	piglit_draw_rect_tex(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
+					     0.0f, 0.0f, 1.0f, 1.0f);
+
+	glDisable(GL_TEXTURE_2D);
+	glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+	glReadPixels(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
+				 GL_RGB, GL_FLOAT, render_data);
+
+	glGetTexImage(GL_TEXTURE_2D,
+				  0, /* level */
+				  GL_RGB,
+				  GL_FLOAT,
+				  get_data);
+
+	pass = compare_precompressed(tex, render_data, is_signed);
+
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glDeleteTextures(1, &tex);
+
+	return pass;
+}
+
+
+static GLuint
+make_float_fbo(GLuint *fbo, GLuint *fbotex)
+{
+	GLenum e;
+	GLuint prev_fbo;
+
+	glGenTextures(1, fbotex);
+	glBindTexture(GL_TEXTURE_2D, *fbotex);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, IMAGE_WIDTH, IMAGE_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	glBindTexture(GL_TEXTURE_2D, 0);
+
+	glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_fbo);
+	glGenFramebuffers(1, fbo);
+	glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *fbotex, 0);
+
+	e = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+	if (e != GL_FRAMEBUFFER_COMPLETE) {
+		fprintf(stderr, "FBO incomplete: error 0x%x\n", e);
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	glClearColor(1,0,0,1);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	return prev_fbo;
+}
+
+
+static void
+draw_float_fbo(GLuint drawfbo, GLuint fbotex)
+{
+	glBindFramebuffer(GL_FRAMEBUFFER, drawfbo);
+	glBindTexture(GL_TEXTURE_2D, fbotex);
+	glEnable(GL_TEXTURE_2D);
+
+	piglit_draw_rect_tex(0, 0, IMAGE_WIDTH * 4, IMAGE_HEIGHT * 4,
+						 0.0f, 0.0f, 1.0f, 1.0f);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glDisable(GL_TEXTURE_2D);
+}
+
+
+static bool
+check_block(const float *image_ref,
+			const float *render_data,
+			const float *get_data)
+{
+	bool overall_result = true;
+	bool pass;
+
+	pass = compare_block_results(image_ref,
+								 render_data);
+	printf("\trender block: %s\n", pass ? "pass" : "fail");
+
+	overall_result &= pass;
+
+	pass = compare_block_results(image_ref,
+								 get_data);
+	printf("\tglGetTexImage: %s\n", pass ? "pass" : "fail");
+
+	overall_result &= pass;
+
+	return overall_result;
+}
+
+
+enum piglit_result
+piglit_display(void)
+{
+	bool pass;
+	float image_ref[IMAGE_WIDTH * IMAGE_HEIGHT * 3];
+	float render_data[IMAGE_WIDTH * IMAGE_HEIGHT * 3];
+	float get_data[IMAGE_WIDTH * IMAGE_HEIGHT * 3];
+	int offset;
+	int x, y;
+	GLuint fbotex, fbo, prev_fbo;
+
+	glClearColor(0, 0, 0, 0);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	prev_fbo = make_float_fbo(&fbo, &fbotex);
+	pass = render_texture(signed_format, compression_hint, image_ref, render_data, get_data);
+	draw_float_fbo(prev_fbo, fbotex);
+
+	glDeleteFramebuffers(1, &fbo);
+	glDeleteTextures(1, &fbotex);
+
+	for (y = 0; y < IMAGE_HEIGHT; y += BLOCK_SIZE) {
+		for (x = 0; x < IMAGE_WIDTH; x += BLOCK_SIZE) {
+			offset = (y * IMAGE_WIDTH + x) * 3;
+			printf ("Checking block %d,%d:\n", x / BLOCK_SIZE, y / BLOCK_SIZE);
+			pass &= check_block(image_ref + offset,
+								render_data + offset,
+								get_data + offset);
+		}
+		puts("");
+	}
+
+	piglit_present_results();
+
+	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}
+
+
+void
+piglit_init(int argc, char **argv)
+{
+	int i;
+	for (i = 1; i < argc; i++) {
+		char *opt = argv[i];
+		if (!strcmp(opt, "dc")) compression_hint = GL_DONT_CARE;
+		else if (!strcmp(opt, "fastest")) compression_hint = GL_FASTEST;
+		else if (!strcmp(opt, "nicest")) compression_hint = GL_NICEST;
+		else if (!strcmp(opt, "unsigned")) signed_format = false;
+		else if (!strcmp(opt, "signed")) signed_format = true;
+	}
+
+
+	if (piglit_get_gl_version() < 42 &&
+	    !piglit_is_extension_supported("GL_ARB_texture_compression_bptc")) {
+		printf("OpenGL 4.2 or GL_ARB_texture_compression_bptc "
+		       "is required.\n");
+		piglit_report_result(PIGLIT_SKIP);
+	}
+
+	if (piglit_get_gl_version() < 30 &&
+		!piglit_is_extension_supported("GL_ARB_color_buffer_float")) {
+		printf("OpenGL 3.0 or GL_ARB_color_buffer_float is required\n");
+		piglit_report_result(PIGLIT_SKIP);
+	}
+
+	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
+}