amd_compressed_atc_texture: add miptree test

Submitted by Jonathan Marek on April 9, 2019, 2:57 p.m.

Details

Message ID 20190409145715.28532-1-jonathan@marek.ca
State New
Headers show
Series "amd_compressed_atc_texture: add miptree test" ( rev: 1 ) in Piglit

Not browsing as part of any series.

Commit Message

Jonathan Marek April 9, 2019, 2:57 p.m.
From: Ilia Mirkin <imirkin@alum.mit.edu>

This echoes the ETC1 miptree test, and even uses the same image.

Updated to work with images created with the open source tool.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
 tests/spec/CMakeLists.txt                     |   1 +
 .../CMakeLists.gles2.txt                      |   6 +
 .../amd_compressed_atc_texture/CMakeLists.txt |   1 +
 .../spec/amd_compressed_atc_texture/miptree.c | 264 ++++++++++++++++++
 .../waffles-compressed-atc-64x32-miptree.dds  | Bin 0 -> 1504 bytes
 ...waffles-decompressed-rgb-64x32-miptree.dds | Bin 0 -> 11048 bytes
 tests/util/CMakeLists.txt                     |   1 +
 tests/util/piglit-dds.c                       | 211 ++++++++++++++
 tests/util/piglit-dds.h                       |  72 +++++
 9 files changed, 556 insertions(+)
 create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
 create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.txt
 create mode 100644 tests/spec/amd_compressed_atc_texture/miptree.c
 create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
 create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
 create mode 100644 tests/util/piglit-dds.c
 create mode 100644 tests/util/piglit-dds.h

Patch hide | download patch | download mbox

diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
index 7f0d3a44e..6169041ff 100644
--- a/tests/spec/CMakeLists.txt
+++ b/tests/spec/CMakeLists.txt
@@ -1,5 +1,6 @@ 
 add_subdirectory (amd_framebuffer_multisample_advanced)
 add_subdirectory (amd_depth_clamp_separate)
+add_subdirectory (amd_compressed_atc_texture)
 add_subdirectory (amd_performance_monitor)
 add_subdirectory (amd_pinned_memory)
 add_subdirectory (arb_arrays_of_arrays)
diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
new file mode 100644
index 000000000..0509e44ae
--- /dev/null
+++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
@@ -0,0 +1,6 @@ 
+include_directories(
+	${GLEXT_INCLUDE_DIR}
+	${OPENGL_INCLUDE_PATH}
+)
+link_libraries(piglitutil_${piglit_target_api})
+piglit_add_executable(amd_compressed_atc_texture-miptree miptree.c)
diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
new file mode 100644
index 000000000..144a306f4
--- /dev/null
+++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
@@ -0,0 +1 @@ 
+piglit_include_target_api()
diff --git a/tests/spec/amd_compressed_atc_texture/miptree.c b/tests/spec/amd_compressed_atc_texture/miptree.c
new file mode 100644
index 000000000..5a2cb044a
--- /dev/null
+++ b/tests/spec/amd_compressed_atc_texture/miptree.c
@@ -0,0 +1,264 @@ 
+/*
+ * Copyright 2012 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
+ * \brief Test texturing from an ATC miptree of a real image.
+ *
+ * Copied from identical ETC1 test.
+ *
+ * This test uses two data files. The file waffles-compressed-atc-64x32.dds
+ * contains a full miptree in GL_ATC_RGB_AMD format of a 2D texture of
+ * waffles and fruit [1].  The base level size is 64x32 pixels. The file
+ * waffles-decompressed-rgb-64x32.dds contains a parallel miptree in GL_RGBA
+ * format. Each of its RGB images was obtained by decompressing the corresponding
+ * ATC image with AMD-supplied Compressonator [2].
+ *
+ * This test draws each miplevel i of the ATC texture such that the image's
+ * lower left corner is at (x=0, y=sum(height of miplevel j for j=0 to i-1)),
+ * and it draws each miplevel of the RGB texture to the right of its
+ * corresponding ETC1 image. Then it compares that the images are identical.
+ *
+ * [1] The reference image is located at http://people.freedesktop.org/~chadversary/permalink/2012-07-09/1574cff2-d091-4421-a3cf-b56c7943d060.jpg.
+ * [2] https://github.com/GPUOpen-Tools/Compressonator
+ */
+
+#include "piglit-util-gl.h"
+#include "piglit-dds.h"
+
+/* note: open Compressonator tool is buggy and fails to generate the 7th 1x1 level */
+#define num_levels 6
+#define level0_width 64
+#define level0_height 32
+
+#define num_vertices 4
+
+static const int window_width = 2 * level0_width;
+static const int window_height = 2 * level0_height;
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_es_version = 20;
+
+	config.window_width = window_width;
+	config.window_height = window_height;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+
+static GLuint prog;
+
+/* Texture objects. */
+static GLuint compressed_tex;
+static GLuint decompressed_tex;
+
+/**
+ * The \a filename is relative to the current test's source directory.
+ *
+ * A new texture is created and returned in \a tex_name.
+ */
+static void
+load_texture(const char *filename, GLuint *tex_name)
+{
+	struct piglit_dds *dds;
+	const struct piglit_dds_info *info;
+	char filepath[4096];
+	int i;
+
+	piglit_join_paths(filepath, sizeof(filepath), 5,
+	                  piglit_source_dir(),
+	                  "tests",
+	                  "spec",
+	                  "amd_compressed_atc_texture",
+	                  filename);
+
+	dds = piglit_dds_read_file(filepath);
+	if (dds == NULL)
+		piglit_report_result(PIGLIT_FAIL);
+
+	info = piglit_dds_get_info(dds);
+	assert(info->num_miplevels >= num_levels);
+	assert(info->pixel_width == level0_width);
+	assert(info->pixel_height== level0_height);
+
+	glGenTextures(1, tex_name);
+	glBindTexture(GL_TEXTURE_2D, *tex_name);
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_levels - 1);
+
+	for (i = 0; i < num_levels; i++) {
+		const struct piglit_dds_image *img = piglit_dds_get_image(dds, i);
+		if (info->gl_internal_format == GL_RGBA)
+			glTexImage2D(GL_TEXTURE_2D, i,
+				     info->gl_internal_format,
+				     img->pixel_width,
+				     img->pixel_height,
+				     0,
+				     GL_RGBA, GL_UNSIGNED_BYTE,
+				     img->data);
+		else
+			glCompressedTexImage2D(GL_TEXTURE_2D, i,
+					       info->gl_internal_format,
+					       img->pixel_width,
+					       img->pixel_height,
+					       0,
+					       img->size,
+					       img->data);
+		if (glGetError())
+			piglit_report_result(PIGLIT_FAIL);
+	}
+
+	piglit_dds_destroy(dds);
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	static const char compressed_filename[] = "waffles-compressed-atc-64x32-miptree.dds";
+	static const char decompressed_filename[] = "waffles-decompressed-rgb-64x32-miptree.dds";
+
+	const char vs_source[] =
+		"#version 100\n"
+		"\n"
+		"uniform vec2 window_pixel_size;\n"
+		"uniform vec2 level_pixel_size;\n"
+		"uniform vec2 pixel_offset;\n"
+		"\n"
+		"// vertex is some corner of the unit square [0,1]^2 \n"
+		"attribute vec2 vertex;\n"
+		"varying vec2 tex_coord;\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"    vec2 pos = vertex;\n"
+		"    pos *= level_pixel_size;\n"
+		"    pos += pixel_offset;\n"
+		"    pos /= 0.5 * window_pixel_size;\n"
+		"    pos -= vec2(1, 1);\n"
+		"    gl_Position = vec4(pos.xy, 0.0, 1.0);\n"
+		"\n"
+		"    tex_coord = vertex;\n"
+		"}\n";
+
+	const char fs_source[] =
+		"#version 100\n"
+		"precision highp float;\n"
+		"\n"
+		"uniform sampler2D tex;\n"
+		"varying vec2 tex_coord;\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"    vec4 t = texture2D(tex, tex_coord);\n"
+		"    gl_FragColor = vec4(t.rgb, 1.0);\n"
+		"}\n";
+
+	/* Draw a square triangle strip. */
+	const GLfloat vertices[2 * num_vertices] = {
+		0, 0,
+		1, 0,
+		1, 1,
+		0, 1,
+	};
+
+	GLint vertex_loc;
+	GLuint vertex_buf;
+
+	piglit_require_extension("GL_AMD_compressed_ATC_texture");
+
+	load_texture(compressed_filename, &compressed_tex);
+	load_texture(decompressed_filename, &decompressed_tex);
+
+	glClearColor(1.0, 0.0, 0.0, 1.0);
+	glViewport(0, 0, window_width, window_height);
+
+	prog = piglit_build_simple_program(vs_source, fs_source);
+	glUseProgram(prog);
+
+	vertex_loc = glGetAttribLocation(prog, "vertex");
+	glGenBuffers(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glEnableVertexAttribArray(vertex_loc);
+	glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
+	             GL_STATIC_DRAW);
+
+	glUniform1i(glGetUniformLocation(prog, "tex"), 0);
+	glActiveTexture(GL_TEXTURE0);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+	glUniform2f(glGetUniformLocation(prog, "window_pixel_size"),
+	            window_width, window_height);
+}
+
+static void
+minify(int *x)
+{
+	assert(*x > 0);
+
+	if (*x > 1)
+		*x >>= 1;
+}
+
+enum piglit_result
+piglit_display(void)
+{
+	GLint pixel_offset_loc = glGetUniformLocation(prog, "pixel_offset");
+	GLint level_pixel_size_loc = glGetUniformLocation(prog, "level_pixel_size");
+
+	int level = 0;
+	int level_width = level0_width;
+	int level_height = level0_height;
+	int y_offset = 0;
+
+	bool pass = true;
+
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	for (level = 0; level < num_levels; ++level) {
+		glUniform2f(level_pixel_size_loc,
+		            (float) level_width,
+		            (float) level_height);
+
+		/* Draw miplevel of compressed texture. */
+		glBindTexture(GL_TEXTURE_2D, compressed_tex);
+		glUniform2f(pixel_offset_loc, 0, y_offset);
+		glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
+
+		/* Draw miplevel of decompressed texture. */
+		glBindTexture(GL_TEXTURE_2D, decompressed_tex);
+		glUniform2f(pixel_offset_loc, level0_width, y_offset);
+		glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
+
+		y_offset += level_height;
+		minify(&level_width);
+		minify(&level_height);
+	}
+
+	pass = piglit_probe_rect_halves_equal_rgba(0, 0, window_width, window_height);
+	piglit_present_results();
+
+	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}
diff --git a/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
new file mode 100644
index 0000000000000000000000000000000000000000..495e565b9ad0c535366c3fdbf92375e54574530f
GIT binary patch
literal 1504
zcma)6Z%k8H6u(bxtF1}9g%KDf(g_Ql-D(zCFqz|(g03=?;;0J{oKnHiPU_rZ)G9^n
zHqDG<nYu3qWl{}7QsZ#hAEYQa0@I{!)c9fc73rf;MeFunZ^6EIb_;PI=9k^%-rv3V
z+<SgEzjMwlEqy=d076KnlA|1gH0fwbYCuT30RMZ;AtxoI8!C;d>2qzVihgd7aWb$s
zDF}=c09gWoc@zScc?5tIRuT*nycmUdtQNBH)kv*r?btz4w6@THZ$L@U$(#Ym%0#Fx
zXE-iZ)PPZUXRKwH3K`Ww03ne87r6((AvBNkev8R8#m~ifK!}+){1;RA$fH-=8-m!S
zS1Q(5dxKO($o#oslnwFcE!S%wiP6cENYgYd0!(+Z`%O@+%4<8EW12+B2KA<|;>l!}
zw0t*thbSbT@jt^qn&x@+rj#AB=p(kP7<>rrs5^~8K**@ukHJgP+ly3__L{ca_ls`y
zLKl^OD0iY8T9HI!IvS@`R}-{lJ1+{{c<cU%Fx&4)kL)o6>P%cU)|T_sPk<Zu^y35<
z4vR!b5EK8tqbJ^vyVIpotLk__RBdhhOf9_yLTtRF$URi7cVubQQ`cxD`PrI3!Ve6D
zPPprz#HE|co5Sz!;4)uSIy-ccUt*{{lQIlG3{TDeI9}@JeJ-iRP@#+W_k}&CJ$)FN
z{h?j1)7U?7s5KSGSwToH#3Py9zI^1SLZQeqF0VKiBSITh(VpwHnbYL1>y%NHOrzWJ
z+Z7M;51LtCWlli-#?hH%Y?1PnsuAviSJEk6^Kt}HJiE>i#0Ys{X&r;pR8)7qZ6Br)
z4PWm56LX0<xa?xUz%JxblIL-X-(oqKJ(z3ilQp2lt?E3xIS}%D3U^-NJeJD3j2lCW
z2T}HZk(*Bt#jZ7W3ceLmWZigy*NZ&zG(L%|kfPD^@m=f>vFu&vJv@sLpKt~-gp+X4
zP7r+G7nIaS&iuW1^oLFD_^H6WIj!y|`&no@BZz&Zz$OZ`L&YQ{=kkw+5d|=z8wppU
z8ki_J5^h1-ryco&VGzULPSn@)UWY<DvD!VRumhB>(FS@$K5tJ`5I8O=rs7&Div2sa
z#J^7|J+9pn8E<qOUem0N_#l0eJo{6(l0rzH{re|GX8)?}wGmW$lD}Bij%i8(w!(*F
zghz3tOiomS6B`<4`0i*Iy8pJERgevLm7GnA;GNp0j?m=(bX5?y_yyRI#}F&%htnAF
zIX0tTGv2Un`*0mB)4XtC#a2YgHQ%@iUre6ed+gF#TlCWF3`TTVEGS_x(RHD|1D3$E
zy0bT={JDxf>T0Z)ovgZPYK+G?V6D09<0T5EZ&|enVv-A`;#W*g#{MEYdp8@{3MYn_
z5VEe$eC(iUx+8xXUoElwzAIQV!#^6ky|QA82YC9mtmy;n9}5ffbwK_d>+<1qhZonJ
zvgUlzla|pOt)tz1X-M?CYag;7Q5$++HSEJ^W>zrSNPe9Hh}Q-2X)$V^Rx^a%K@IB6
z0r_0iyRuNuqHdTonq;il8v)stW|EIBoL$R+DEbuTdCiZ{Y)a{$&8(p4%2k^7$Eb}L
zFPKt(x>2ry0ey``b)#r~JiB?e)3%!=T{6K9<@O9w9d=;r-?~F|43y{fVT<UHt<sSH
lp{XQ%z9I-N38F{K0LI6<N+MNvCx_1tpM7u3<y$vN`v-g6D{TM(

literal 0
HcmV?d00001

diff --git a/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
new file mode 100644
index 0000000000000000000000000000000000000000..a5b47df2b828feef99e283be042a24631e422098
GIT binary patch
literal 11048
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
C>eV{{

literal 0
HcmV?d00001

diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt
index a5f080156..f6a2b69a9 100644
--- a/tests/util/CMakeLists.txt
+++ b/tests/util/CMakeLists.txt
@@ -48,6 +48,7 @@  set(UTIL_GL_INCLUDES
 set(UTIL_GL_SOURCES
 	fdo-bitmap.c
 	minmax-test.c
+	piglit-dds.c
 	piglit-dispatch.c
 	piglit-dispatch-init.c
 	piglit-fbo.cpp
diff --git a/tests/util/piglit-dds.c b/tests/util/piglit-dds.c
new file mode 100644
index 000000000..2ab6e6af5
--- /dev/null
+++ b/tests/util/piglit-dds.c
@@ -0,0 +1,211 @@ 
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "piglit-dds.h"
+#include "piglit-util-gl.h"
+
+
+// DDS values taken from http://www.mindcontrol.org/~hplus/graphics/dds-info/
+
+//  little-endian, of course
+
+//  DDS_header.dwFlags
+#define DDSD_CAPS                   0x00000001
+#define DDSD_HEIGHT                 0x00000002
+#define DDSD_WIDTH                  0x00000004
+#define DDSD_PITCH                  0x00000008
+#define DDSD_PIXELFORMAT            0x00001000
+#define DDSD_MIPMAPCOUNT            0x00020000
+#define DDSD_LINEARSIZE             0x00080000
+#define DDSD_DEPTH                  0x00800000
+
+//  DDS_header.sPixelFormat.dwFlags
+#define DDPF_ALPHAPIXELS            0x00000001
+#define DDPF_FOURCC                 0x00000004
+#define DDPF_INDEXED                0x00000020
+#define DDPF_RGB                    0x00000040
+
+//  DDS_header.sCaps.dwCaps1
+#define DDSCAPS_COMPLEX             0x00000008
+#define DDSCAPS_TEXTURE             0x00001000
+#define DDSCAPS_MIPMAP              0x00400000
+
+//  DDS_header.sCaps.dwCaps2
+#define DDSCAPS2_CUBEMAP            0x00000200
+#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
+#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
+#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
+#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
+#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
+#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
+#define DDSCAPS2_VOLUME             0x00200000
+
+union DDS_header {
+	struct {
+		unsigned int    dwMagic;
+		unsigned int    dwSize;
+		unsigned int    dwFlags;
+		unsigned int    dwHeight;
+		unsigned int    dwWidth;
+		unsigned int    dwPitchOrLinearSize;
+		unsigned int    dwDepth;
+		unsigned int    dwMipMapCount;
+		unsigned int    dwReserved1[ 11 ];
+
+		//  DDPIXELFORMAT
+		struct {
+			unsigned int    dwSize;
+			unsigned int    dwFlags;
+			unsigned int    dwFourCC;
+			unsigned int    dwRGBBitCount;
+			unsigned int    dwRBitMask;
+			unsigned int    dwGBitMask;
+			unsigned int    dwBBitMask;
+			unsigned int    dwAlphaBitMask;
+		}               sPixelFormat;
+
+		//  DDCAPS2
+		struct {
+			unsigned int    dwCaps1;
+			unsigned int    dwCaps2;
+			unsigned int    dwDDSX;
+			unsigned int    dwReserved;
+		}               sCaps;
+		unsigned int    dwReserved2;
+	};
+	char data[ 128 ];
+};
+
+#define FOURCC(a, b, c, d)  ((a) << 0 | (b) << 8 | (c) << 16 | (d) << 24)
+
+#define DDS_MAGIC   FOURCC('D', 'D', 'S', ' ')
+#define ATC_RGB     FOURCC('A', 'T', 'C', ' ')
+#define ATC_RGBA_E  FOURCC('A', 'T', 'C', 'A')
+#define ATC_RGBA_I  FOURCC('A', 'T', 'C', 'I')
+
+struct piglit_dds {
+	struct piglit_dds_info info;
+	uint8_t *data;
+	size_t size;
+
+	struct piglit_dds_image *images;
+};
+
+void
+piglit_dds_destroy(struct piglit_dds *self)
+{
+	free(self->images);
+	free(self->data);
+	free(self);
+}
+
+struct piglit_dds *
+piglit_dds_read_file(const char *filename)
+{
+	struct piglit_dds *ret = calloc(1, sizeof(struct piglit_dds));
+	FILE *f;
+	bool success = false;
+	int read, i, shift = 0, factor = 0;
+	union DDS_header *header;
+
+	if (!ret)
+		goto err_ret;
+
+	f = fopen(filename, "rb");
+
+	if (!f)
+		goto err_file;
+
+	if (fseek(f, 0, SEEK_END))
+		goto err_read;
+	ret->size = ftell(f);
+	if (fseek(f, 0, SEEK_SET))
+		goto err_read;
+
+	ret->data = malloc(ret->size);
+	if (!ret->data)
+		goto err_read;
+
+	read = fread(ret->data, 1, ret->size, f);
+	if (read < ret->size)
+		goto err_read;
+
+	header = (union DDS_header*) ret->data;
+
+	if (header->dwMagic != DDS_MAGIC)
+		goto err_read;
+
+	ret->info.num_miplevels = header->dwMipMapCount;
+	ret->info.pixel_width = header->dwWidth;
+	ret->info.pixel_height = header->dwHeight;
+	switch (header->sPixelFormat.dwFourCC) {
+	case 0:
+		ret->info.gl_internal_format = GL_RGBA;
+		factor = 4;
+		break;
+	case ATC_RGB:
+		ret->info.gl_internal_format = GL_ATC_RGB_AMD;
+		shift = 1;
+		break;
+	case ATC_RGBA_I:
+		ret->info.gl_internal_format = GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
+		break;
+	case ATC_RGBA_E:
+		ret->info.gl_internal_format = GL_ATC_RGBA_EXPLICIT_ALPHA_AMD;
+		break;
+	default:
+		goto err_read;
+	}
+
+	ret->images = calloc(ret->info.num_miplevels, sizeof(struct piglit_dds_image));
+	for (i = 0; i < ret->info.num_miplevels; i++) {
+		struct piglit_dds_image *img = &ret->images[i];
+		if (i == 0) {
+			img->data = ret->data + 128;
+			img->pixel_width = ret->info.pixel_width;
+			img->pixel_height = ret->info.pixel_height;
+		} else {
+			struct piglit_dds_image *prev = &ret->images[i - 1];
+			img->data = prev->data + prev->size;
+			img->pixel_width = MAX2(1, prev->pixel_width >> 1);
+			img->pixel_height = MAX2(1, prev->pixel_height >> 1);
+		}
+		if (header->sPixelFormat.dwFourCC)
+			img->size = ALIGN(img->pixel_width, 4) * ALIGN(img->pixel_height, 4);
+		else
+			img->size = img->pixel_width * img->pixel_height;
+		if (shift > 0)
+			img->size >>= shift;
+		if (factor > 0)
+			img->size *= factor;
+	}
+
+	success = true;
+
+err_read:
+	fclose(f);
+	if (success)
+		return ret;
+	if (ret->data)
+		free(ret->data);
+err_file:
+	free(ret);
+err_ret:
+	return NULL;
+}
+
+const struct piglit_dds_info *
+piglit_dds_get_info(struct piglit_dds *self)
+{
+	return &self->info;
+}
+
+const struct piglit_dds_image *
+piglit_dds_get_image(struct piglit_dds *self,
+                     int miplevel)
+{
+	assert(miplevel < self->info.num_miplevels);
+	return &self->images[miplevel];
+}
diff --git a/tests/util/piglit-dds.h b/tests/util/piglit-dds.h
new file mode 100644
index 000000000..28660b99d
--- /dev/null
+++ b/tests/util/piglit-dds.h
@@ -0,0 +1,72 @@ 
+/*
+ * Copyright 2015 Ilia Mirkin
+ *
+ * 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
+ *
+ * \brief Utilities for the DDS file format
+ *
+ * The DDS file format specifies a simple format for storing texture
+ * miptrees.
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct piglit_dds;
+
+struct piglit_dds_info {
+  uint32_t gl_internal_format;
+  uint32_t num_miplevels;
+
+  uint32_t pixel_width;
+  uint32_t pixel_height;
+};
+
+struct piglit_dds_image {
+  const uint8_t *data;
+  size_t size;
+
+  uint32_t pixel_width;
+  uint32_t pixel_height;
+};
+
+void
+piglit_dds_destroy(struct piglit_dds *self);
+
+struct piglit_dds *
+piglit_dds_read_file(const char *filename);
+
+const struct piglit_dds_info *
+piglit_dds_get_info(struct piglit_dds *self);
+
+const struct piglit_dds_image *
+piglit_dds_get_image(struct piglit_dds *self,
+                     int miplevel);
+
+#ifdef __cplusplus
+}
+#endif

Comments

Back when I did this, DDS was the only output format supported by the
tool I was using, and while I thought about converting to KTX "by
hand", that seemed sufficiently unpleasant (I don't remember all the
details, TBH -- it's been 4 years, seemingly). Does the new tool
support KTX output, or still just DDS only? If it supports KTX,
there's existing infra in piglit to process it.

Also, for the miptree.c header - can you include a mention that it was
based on the miptree.c from the ASTC tests? Otherwise the Intel
copyright is fairly unclear.

On Tue, Apr 9, 2019 at 10:58 AM Jonathan Marek <jonathan@marek.ca> wrote:
>
> From: Ilia Mirkin <imirkin@alum.mit.edu>
>
> This echoes the ETC1 miptree test, and even uses the same image.
>
> Updated to work with images created with the open source tool.
>
> Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
> ---
>  tests/spec/CMakeLists.txt                     |   1 +
>  .../CMakeLists.gles2.txt                      |   6 +
>  .../amd_compressed_atc_texture/CMakeLists.txt |   1 +
>  .../spec/amd_compressed_atc_texture/miptree.c | 264 ++++++++++++++++++
>  .../waffles-compressed-atc-64x32-miptree.dds  | Bin 0 -> 1504 bytes
>  ...waffles-decompressed-rgb-64x32-miptree.dds | Bin 0 -> 11048 bytes
>  tests/util/CMakeLists.txt                     |   1 +
>  tests/util/piglit-dds.c                       | 211 ++++++++++++++
>  tests/util/piglit-dds.h                       |  72 +++++
>  9 files changed, 556 insertions(+)
>  create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
>  create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.txt
>  create mode 100644 tests/spec/amd_compressed_atc_texture/miptree.c
>  create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
>  create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
>  create mode 100644 tests/util/piglit-dds.c
>  create mode 100644 tests/util/piglit-dds.h
>
> diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
> index 7f0d3a44e..6169041ff 100644
> --- a/tests/spec/CMakeLists.txt
> +++ b/tests/spec/CMakeLists.txt
> @@ -1,5 +1,6 @@
>  add_subdirectory (amd_framebuffer_multisample_advanced)
>  add_subdirectory (amd_depth_clamp_separate)
> +add_subdirectory (amd_compressed_atc_texture)
>  add_subdirectory (amd_performance_monitor)
>  add_subdirectory (amd_pinned_memory)
>  add_subdirectory (arb_arrays_of_arrays)
> diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
> new file mode 100644
> index 000000000..0509e44ae
> --- /dev/null
> +++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
> @@ -0,0 +1,6 @@
> +include_directories(
> +       ${GLEXT_INCLUDE_DIR}
> +       ${OPENGL_INCLUDE_PATH}
> +)
> +link_libraries(piglitutil_${piglit_target_api})
> +piglit_add_executable(amd_compressed_atc_texture-miptree miptree.c)
> diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
> new file mode 100644
> index 000000000..144a306f4
> --- /dev/null
> +++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
> @@ -0,0 +1 @@
> +piglit_include_target_api()
> diff --git a/tests/spec/amd_compressed_atc_texture/miptree.c b/tests/spec/amd_compressed_atc_texture/miptree.c
> new file mode 100644
> index 000000000..5a2cb044a
> --- /dev/null
> +++ b/tests/spec/amd_compressed_atc_texture/miptree.c
> @@ -0,0 +1,264 @@
> +/*
> + * Copyright 2012 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
> + * \brief Test texturing from an ATC miptree of a real image.
> + *
> + * Copied from identical ETC1 test.
> + *
> + * This test uses two data files. The file waffles-compressed-atc-64x32.dds
> + * contains a full miptree in GL_ATC_RGB_AMD format of a 2D texture of
> + * waffles and fruit [1].  The base level size is 64x32 pixels. The file
> + * waffles-decompressed-rgb-64x32.dds contains a parallel miptree in GL_RGBA
> + * format. Each of its RGB images was obtained by decompressing the corresponding
> + * ATC image with AMD-supplied Compressonator [2].
> + *
> + * This test draws each miplevel i of the ATC texture such that the image's
> + * lower left corner is at (x=0, y=sum(height of miplevel j for j=0 to i-1)),
> + * and it draws each miplevel of the RGB texture to the right of its
> + * corresponding ETC1 image. Then it compares that the images are identical.
> + *
> + * [1] The reference image is located at http://people.freedesktop.org/~chadversary/permalink/2012-07-09/1574cff2-d091-4421-a3cf-b56c7943d060.jpg.
> + * [2] https://github.com/GPUOpen-Tools/Compressonator
> + */
> +
> +#include "piglit-util-gl.h"
> +#include "piglit-dds.h"
> +
> +/* note: open Compressonator tool is buggy and fails to generate the 7th 1x1 level */
> +#define num_levels 6
> +#define level0_width 64
> +#define level0_height 32
> +
> +#define num_vertices 4
> +
> +static const int window_width = 2 * level0_width;
> +static const int window_height = 2 * level0_height;
> +
> +PIGLIT_GL_TEST_CONFIG_BEGIN
> +
> +       config.supports_gl_es_version = 20;
> +
> +       config.window_width = window_width;
> +       config.window_height = window_height;
> +       config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
> +
> +PIGLIT_GL_TEST_CONFIG_END
> +
> +
> +static GLuint prog;
> +
> +/* Texture objects. */
> +static GLuint compressed_tex;
> +static GLuint decompressed_tex;
> +
> +/**
> + * The \a filename is relative to the current test's source directory.
> + *
> + * A new texture is created and returned in \a tex_name.
> + */
> +static void
> +load_texture(const char *filename, GLuint *tex_name)
> +{
> +       struct piglit_dds *dds;
> +       const struct piglit_dds_info *info;
> +       char filepath[4096];
> +       int i;
> +
> +       piglit_join_paths(filepath, sizeof(filepath), 5,
> +                         piglit_source_dir(),
> +                         "tests",
> +                         "spec",
> +                         "amd_compressed_atc_texture",
> +                         filename);
> +
> +       dds = piglit_dds_read_file(filepath);
> +       if (dds == NULL)
> +               piglit_report_result(PIGLIT_FAIL);
> +
> +       info = piglit_dds_get_info(dds);
> +       assert(info->num_miplevels >= num_levels);
> +       assert(info->pixel_width == level0_width);
> +       assert(info->pixel_height== level0_height);
> +
> +       glGenTextures(1, tex_name);
> +       glBindTexture(GL_TEXTURE_2D, *tex_name);
> +       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_levels - 1);
> +
> +       for (i = 0; i < num_levels; i++) {
> +               const struct piglit_dds_image *img = piglit_dds_get_image(dds, i);
> +               if (info->gl_internal_format == GL_RGBA)
> +                       glTexImage2D(GL_TEXTURE_2D, i,
> +                                    info->gl_internal_format,
> +                                    img->pixel_width,
> +                                    img->pixel_height,
> +                                    0,
> +                                    GL_RGBA, GL_UNSIGNED_BYTE,
> +                                    img->data);
> +               else
> +                       glCompressedTexImage2D(GL_TEXTURE_2D, i,
> +                                              info->gl_internal_format,
> +                                              img->pixel_width,
> +                                              img->pixel_height,
> +                                              0,
> +                                              img->size,
> +                                              img->data);
> +               if (glGetError())
> +                       piglit_report_result(PIGLIT_FAIL);
> +       }
> +
> +       piglit_dds_destroy(dds);
> +}
> +
> +void
> +piglit_init(int argc, char **argv)
> +{
> +       static const char compressed_filename[] = "waffles-compressed-atc-64x32-miptree.dds";
> +       static const char decompressed_filename[] = "waffles-decompressed-rgb-64x32-miptree.dds";
> +
> +       const char vs_source[] =
> +               "#version 100\n"
> +               "\n"
> +               "uniform vec2 window_pixel_size;\n"
> +               "uniform vec2 level_pixel_size;\n"
> +               "uniform vec2 pixel_offset;\n"
> +               "\n"
> +               "// vertex is some corner of the unit square [0,1]^2 \n"
> +               "attribute vec2 vertex;\n"
> +               "varying vec2 tex_coord;\n"
> +               "\n"
> +               "void main()\n"
> +               "{\n"
> +               "    vec2 pos = vertex;\n"
> +               "    pos *= level_pixel_size;\n"
> +               "    pos += pixel_offset;\n"
> +               "    pos /= 0.5 * window_pixel_size;\n"
> +               "    pos -= vec2(1, 1);\n"
> +               "    gl_Position = vec4(pos.xy, 0.0, 1.0);\n"
> +               "\n"
> +               "    tex_coord = vertex;\n"
> +               "}\n";
> +
> +       const char fs_source[] =
> +               "#version 100\n"
> +               "precision highp float;\n"
> +               "\n"
> +               "uniform sampler2D tex;\n"
> +               "varying vec2 tex_coord;\n"
> +               "\n"
> +               "void main()\n"
> +               "{\n"
> +               "    vec4 t = texture2D(tex, tex_coord);\n"
> +               "    gl_FragColor = vec4(t.rgb, 1.0);\n"
> +               "}\n";
> +
> +       /* Draw a square triangle strip. */
> +       const GLfloat vertices[2 * num_vertices] = {
> +               0, 0,
> +               1, 0,
> +               1, 1,
> +               0, 1,
> +       };
> +
> +       GLint vertex_loc;
> +       GLuint vertex_buf;
> +
> +       piglit_require_extension("GL_AMD_compressed_ATC_texture");
> +
> +       load_texture(compressed_filename, &compressed_tex);
> +       load_texture(decompressed_filename, &decompressed_tex);
> +
> +       glClearColor(1.0, 0.0, 0.0, 1.0);
> +       glViewport(0, 0, window_width, window_height);
> +
> +       prog = piglit_build_simple_program(vs_source, fs_source);
> +       glUseProgram(prog);
> +
> +       vertex_loc = glGetAttribLocation(prog, "vertex");
> +       glGenBuffers(1, &vertex_buf);
> +       glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
> +       glEnableVertexAttribArray(vertex_loc);
> +       glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
> +       glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
> +                    GL_STATIC_DRAW);
> +
> +       glUniform1i(glGetUniformLocation(prog, "tex"), 0);
> +       glActiveTexture(GL_TEXTURE0);
> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
> +
> +       glUniform2f(glGetUniformLocation(prog, "window_pixel_size"),
> +                   window_width, window_height);
> +}
> +
> +static void
> +minify(int *x)
> +{
> +       assert(*x > 0);
> +
> +       if (*x > 1)
> +               *x >>= 1;
> +}
> +
> +enum piglit_result
> +piglit_display(void)
> +{
> +       GLint pixel_offset_loc = glGetUniformLocation(prog, "pixel_offset");
> +       GLint level_pixel_size_loc = glGetUniformLocation(prog, "level_pixel_size");
> +
> +       int level = 0;
> +       int level_width = level0_width;
> +       int level_height = level0_height;
> +       int y_offset = 0;
> +
> +       bool pass = true;
> +
> +       glClear(GL_COLOR_BUFFER_BIT);
> +
> +       for (level = 0; level < num_levels; ++level) {
> +               glUniform2f(level_pixel_size_loc,
> +                           (float) level_width,
> +                           (float) level_height);
> +
> +               /* Draw miplevel of compressed texture. */
> +               glBindTexture(GL_TEXTURE_2D, compressed_tex);
> +               glUniform2f(pixel_offset_loc, 0, y_offset);
> +               glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
> +
> +               /* Draw miplevel of decompressed texture. */
> +               glBindTexture(GL_TEXTURE_2D, decompressed_tex);
> +               glUniform2f(pixel_offset_loc, level0_width, y_offset);
> +               glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
> +
> +               y_offset += level_height;
> +               minify(&level_width);
> +               minify(&level_height);
> +       }
> +
> +       pass = piglit_probe_rect_halves_equal_rgba(0, 0, window_width, window_height);
> +       piglit_present_results();
> +
> +       return pass ? PIGLIT_PASS : PIGLIT_FAIL;
> +}
> diff --git a/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
> new file mode 100644
> index 0000000000000000000000000000000000000000..495e565b9ad0c535366c3fdbf92375e54574530f
> GIT binary patch
> literal 1504
> zcma)6Z%k8H6u(bxtF1}9g%KDf(g_Ql-D(zCFqz|(g03=?;;0J{oKnHiPU_rZ)G9^n
> zHqDG<nYu3qWl{}7QsZ#hAEYQa0@I{!)c9fc73rf;MeFunZ^6EIb_;PI=9k^%-rv3V
> z+<SgEzjMwlEqy=d076KnlA|1gH0fwbYCuT30RMZ;AtxoI8!C;d>2qzVihgd7aWb$s
> zDF}=c09gWoc@zScc?5tIRuT*nycmUdtQNBH)kv*r?btz4w6@THZ$L@U$(#Ym%0#Fx
> zXE-iZ)PPZUXRKwH3K`Ww03ne87r6((AvBNkev8R8#m~ifK!}+){1;RA$fH-=8-m!S
> zS1Q(5dxKO($o#oslnwFcE!S%wiP6cENYgYd0!(+Z`%O@+%4<8EW12+B2KA<|;>l!}
> zw0t*thbSbT@jt^qn&x@+rj#AB=p(kP7<>rrs5^~8K**@ukHJgP+ly3__L{ca_ls`y
> zLKl^OD0iY8T9HI!IvS@`R}-{lJ1+{{c<cU%Fx&4)kL)o6>P%cU)|T_sPk<Zu^y35<
> z4vR!b5EK8tqbJ^vyVIpotLk__RBdhhOf9_yLTtRF$URi7cVubQQ`cxD`PrI3!Ve6D
> zPPprz#HE|co5Sz!;4)uSIy-ccUt*{{lQIlG3{TDeI9}@JeJ-iRP@#+W_k}&CJ$)FN
> z{h?j1)7U?7s5KSGSwToH#3Py9zI^1SLZQeqF0VKiBSITh(VpwHnbYL1>y%NHOrzWJ
> z+Z7M;51LtCWlli-#?hH%Y?1PnsuAviSJEk6^Kt}HJiE>i#0Ys{X&r;pR8)7qZ6Br)
> z4PWm56LX0<xa?xUz%JxblIL-X-(oqKJ(z3ilQp2lt?E3xIS}%D3U^-NJeJD3j2lCW
> z2T}HZk(*Bt#jZ7W3ceLmWZigy*NZ&zG(L%|kfPD^@m=f>vFu&vJv@sLpKt~-gp+X4
> zP7r+G7nIaS&iuW1^oLFD_^H6WIj!y|`&no@BZz&Zz$OZ`L&YQ{=kkw+5d|=z8wppU
> z8ki_J5^h1-ryco&VGzULPSn@)UWY<DvD!VRumhB>(FS@$K5tJ`5I8O=rs7&Div2sa
> z#J^7|J+9pn8E<qOUem0N_#l0eJo{6(l0rzH{re|GX8)?}wGmW$lD}Bij%i8(w!(*F
> zghz3tOiomS6B`<4`0i*Iy8pJERgevLm7GnA;GNp0j?m=(bX5?y_yyRI#}F&%htnAF
> zIX0tTGv2Un`*0mB)4XtC#a2YgHQ%@iUre6ed+gF#TlCWF3`TTVEGS_x(RHD|1D3$E
> zy0bT={JDxf>T0Z)ovgZPYK+G?V6D09<0T5EZ&|enVv-A`;#W*g#{MEYdp8@{3MYn_
> z5VEe$eC(iUx+8xXUoElwzAIQV!#^6ky|QA82YC9mtmy;n9}5ffbwK_d>+<1qhZonJ
> zvgUlzla|pOt)tz1X-M?CYag;7Q5$++HSEJ^W>zrSNPe9Hh}Q-2X)$V^Rx^a%K@IB6
> z0r_0iyRuNuqHdTonq;il8v)stW|EIBoL$R+DEbuTdCiZ{Y)a{$&8(p4%2k^7$Eb}L
> zFPKt(x>2ry0ey``b)#r~JiB?e)3%!=T{6K9<@O9w9d=;r-?~F|43y{fVT<UHt<sSH
> lp{XQ%z9I-N38F{K0LI6<N+MNvCx_1tpM7u3<y$vN`v-g6D{TM(
>
> literal 0
> HcmV?d00001
>
> diff --git a/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
> new file mode 100644
> index 0000000000000000000000000000000000000000..a5b47df2b828feef99e283be042a24631e422098
> GIT binary patch
> literal 11048
> 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
> C>eV{{
>
> literal 0
> HcmV?d00001
>
> diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt
> index a5f080156..f6a2b69a9 100644
> --- a/tests/util/CMakeLists.txt
> +++ b/tests/util/CMakeLists.txt
> @@ -48,6 +48,7 @@ set(UTIL_GL_INCLUDES
>  set(UTIL_GL_SOURCES
>         fdo-bitmap.c
>         minmax-test.c
> +       piglit-dds.c
>         piglit-dispatch.c
>         piglit-dispatch-init.c
>         piglit-fbo.cpp
> diff --git a/tests/util/piglit-dds.c b/tests/util/piglit-dds.c
> new file mode 100644
> index 000000000..2ab6e6af5
> --- /dev/null
> +++ b/tests/util/piglit-dds.c
> @@ -0,0 +1,211 @@
> +#include <assert.h>
> +#include <stdarg.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "piglit-dds.h"
> +#include "piglit-util-gl.h"
> +
> +
> +// DDS values taken from http://www.mindcontrol.org/~hplus/graphics/dds-info/
> +
> +//  little-endian, of course
> +
> +//  DDS_header.dwFlags
> +#define DDSD_CAPS                   0x00000001
> +#define DDSD_HEIGHT                 0x00000002
> +#define DDSD_WIDTH                  0x00000004
> +#define DDSD_PITCH                  0x00000008
> +#define DDSD_PIXELFORMAT            0x00001000
> +#define DDSD_MIPMAPCOUNT            0x00020000
> +#define DDSD_LINEARSIZE             0x00080000
> +#define DDSD_DEPTH                  0x00800000
> +
> +//  DDS_header.sPixelFormat.dwFlags
> +#define DDPF_ALPHAPIXELS            0x00000001
> +#define DDPF_FOURCC                 0x00000004
> +#define DDPF_INDEXED                0x00000020
> +#define DDPF_RGB                    0x00000040
> +
> +//  DDS_header.sCaps.dwCaps1
> +#define DDSCAPS_COMPLEX             0x00000008
> +#define DDSCAPS_TEXTURE             0x00001000
> +#define DDSCAPS_MIPMAP              0x00400000
> +
> +//  DDS_header.sCaps.dwCaps2
> +#define DDSCAPS2_CUBEMAP            0x00000200
> +#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
> +#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
> +#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
> +#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
> +#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
> +#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
> +#define DDSCAPS2_VOLUME             0x00200000
> +
> +union DDS_header {
> +       struct {
> +               unsigned int    dwMagic;
> +               unsigned int    dwSize;
> +               unsigned int    dwFlags;
> +               unsigned int    dwHeight;
> +               unsigned int    dwWidth;
> +               unsigned int    dwPitchOrLinearSize;
> +               unsigned int    dwDepth;
> +               unsigned int    dwMipMapCount;
> +               unsigned int    dwReserved1[ 11 ];
> +
> +               //  DDPIXELFORMAT
> +               struct {
> +                       unsigned int    dwSize;
> +                       unsigned int    dwFlags;
> +                       unsigned int    dwFourCC;
> +                       unsigned int    dwRGBBitCount;
> +                       unsigned int    dwRBitMask;
> +                       unsigned int    dwGBitMask;
> +                       unsigned int    dwBBitMask;
> +                       unsigned int    dwAlphaBitMask;
> +               }               sPixelFormat;
> +
> +               //  DDCAPS2
> +               struct {
> +                       unsigned int    dwCaps1;
> +                       unsigned int    dwCaps2;
> +                       unsigned int    dwDDSX;
> +                       unsigned int    dwReserved;
> +               }               sCaps;
> +               unsigned int    dwReserved2;
> +       };
> +       char data[ 128 ];
> +};
> +
> +#define FOURCC(a, b, c, d)  ((a) << 0 | (b) << 8 | (c) << 16 | (d) << 24)
> +
> +#define DDS_MAGIC   FOURCC('D', 'D', 'S', ' ')
> +#define ATC_RGB     FOURCC('A', 'T', 'C', ' ')
> +#define ATC_RGBA_E  FOURCC('A', 'T', 'C', 'A')
> +#define ATC_RGBA_I  FOURCC('A', 'T', 'C', 'I')
> +
> +struct piglit_dds {
> +       struct piglit_dds_info info;
> +       uint8_t *data;
> +       size_t size;
> +
> +       struct piglit_dds_image *images;
> +};
> +
> +void
> +piglit_dds_destroy(struct piglit_dds *self)
> +{
> +       free(self->images);
> +       free(self->data);
> +       free(self);
> +}
> +
> +struct piglit_dds *
> +piglit_dds_read_file(const char *filename)
> +{
> +       struct piglit_dds *ret = calloc(1, sizeof(struct piglit_dds));
> +       FILE *f;
> +       bool success = false;
> +       int read, i, shift = 0, factor = 0;
> +       union DDS_header *header;
> +
> +       if (!ret)
> +               goto err_ret;
> +
> +       f = fopen(filename, "rb");
> +
> +       if (!f)
> +               goto err_file;
> +
> +       if (fseek(f, 0, SEEK_END))
> +               goto err_read;
> +       ret->size = ftell(f);
> +       if (fseek(f, 0, SEEK_SET))
> +               goto err_read;
> +
> +       ret->data = malloc(ret->size);
> +       if (!ret->data)
> +               goto err_read;
> +
> +       read = fread(ret->data, 1, ret->size, f);
> +       if (read < ret->size)
> +               goto err_read;
> +
> +       header = (union DDS_header*) ret->data;
> +
> +       if (header->dwMagic != DDS_MAGIC)
> +               goto err_read;
> +
> +       ret->info.num_miplevels = header->dwMipMapCount;
> +       ret->info.pixel_width = header->dwWidth;
> +       ret->info.pixel_height = header->dwHeight;
> +       switch (header->sPixelFormat.dwFourCC) {
> +       case 0:
> +               ret->info.gl_internal_format = GL_RGBA;
> +               factor = 4;
> +               break;
> +       case ATC_RGB:
> +               ret->info.gl_internal_format = GL_ATC_RGB_AMD;
> +               shift = 1;
> +               break;
> +       case ATC_RGBA_I:
> +               ret->info.gl_internal_format = GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
> +               break;
> +       case ATC_RGBA_E:
> +               ret->info.gl_internal_format = GL_ATC_RGBA_EXPLICIT_ALPHA_AMD;
> +               break;
> +       default:
> +               goto err_read;
> +       }
> +
> +       ret->images = calloc(ret->info.num_miplevels, sizeof(struct piglit_dds_image));
> +       for (i = 0; i < ret->info.num_miplevels; i++) {
> +               struct piglit_dds_image *img = &ret->images[i];
> +               if (i == 0) {
> +                       img->data = ret->data + 128;
> +                       img->pixel_width = ret->info.pixel_width;
> +                       img->pixel_height = ret->info.pixel_height;
> +               } else {
> +                       struct piglit_dds_image *prev = &ret->images[i - 1];
> +                       img->data = prev->data + prev->size;
> +                       img->pixel_width = MAX2(1, prev->pixel_width >> 1);
> +                       img->pixel_height = MAX2(1, prev->pixel_height >> 1);
> +               }
> +               if (header->sPixelFormat.dwFourCC)
> +                       img->size = ALIGN(img->pixel_width, 4) * ALIGN(img->pixel_height, 4);
> +               else
> +                       img->size = img->pixel_width * img->pixel_height;
> +               if (shift > 0)
> +                       img->size >>= shift;
> +               if (factor > 0)
> +                       img->size *= factor;
> +       }
> +
> +       success = true;
> +
> +err_read:
> +       fclose(f);
> +       if (success)
> +               return ret;
> +       if (ret->data)
> +               free(ret->data);
> +err_file:
> +       free(ret);
> +err_ret:
> +       return NULL;
> +}
> +
> +const struct piglit_dds_info *
> +piglit_dds_get_info(struct piglit_dds *self)
> +{
> +       return &self->info;
> +}
> +
> +const struct piglit_dds_image *
> +piglit_dds_get_image(struct piglit_dds *self,
> +                     int miplevel)
> +{
> +       assert(miplevel < self->info.num_miplevels);
> +       return &self->images[miplevel];
> +}
> diff --git a/tests/util/piglit-dds.h b/tests/util/piglit-dds.h
> new file mode 100644
> index 000000000..28660b99d
> --- /dev/null
> +++ b/tests/util/piglit-dds.h
> @@ -0,0 +1,72 @@
> +/*
> + * Copyright 2015 Ilia Mirkin
> + *
> + * 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
> + *
> + * \brief Utilities for the DDS file format
> + *
> + * The DDS file format specifies a simple format for storing texture
> + * miptrees.
> + */
> +
> +#include <stdint.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +struct piglit_dds;
> +
> +struct piglit_dds_info {
> +  uint32_t gl_internal_format;
> +  uint32_t num_miplevels;
> +
> +  uint32_t pixel_width;
> +  uint32_t pixel_height;
> +};
> +
> +struct piglit_dds_image {
> +  const uint8_t *data;
> +  size_t size;
> +
> +  uint32_t pixel_width;
> +  uint32_t pixel_height;
> +};
> +
> +void
> +piglit_dds_destroy(struct piglit_dds *self);
> +
> +struct piglit_dds *
> +piglit_dds_read_file(const char *filename);
> +
> +const struct piglit_dds_info *
> +piglit_dds_get_info(struct piglit_dds *self);
> +
> +const struct piglit_dds_image *
> +piglit_dds_get_image(struct piglit_dds *self,
> +                     int miplevel);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> --
> 2.17.1
>
Yes, the tool supports KTX. I made a new version of the patch with a new 
copy of the ETC1 test which uses KTX and dropped the DDS loader.

The comment after the copyright header says it is copied from ETC1 
miptree test, so I guess its already OK?

On 4/9/19 12:48 PM, Ilia Mirkin wrote:
> Back when I did this, DDS was the only output format supported by the
> tool I was using, and while I thought about converting to KTX "by
> hand", that seemed sufficiently unpleasant (I don't remember all the
> details, TBH -- it's been 4 years, seemingly). Does the new tool
> support KTX output, or still just DDS only? If it supports KTX,
> there's existing infra in piglit to process it.
> 
> Also, for the miptree.c header - can you include a mention that it was
> based on the miptree.c from the ASTC tests? Otherwise the Intel
> copyright is fairly unclear.
> 
> On Tue, Apr 9, 2019 at 10:58 AM Jonathan Marek <jonathan@marek.ca> wrote:
>>
>> From: Ilia Mirkin <imirkin@alum.mit.edu>
>>
>> This echoes the ETC1 miptree test, and even uses the same image.
>>
>> Updated to work with images created with the open source tool.
>>
>> Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
>> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
>> ---
>>   tests/spec/CMakeLists.txt                     |   1 +
>>   .../CMakeLists.gles2.txt                      |   6 +
>>   .../amd_compressed_atc_texture/CMakeLists.txt |   1 +
>>   .../spec/amd_compressed_atc_texture/miptree.c | 264 ++++++++++++++++++
>>   .../waffles-compressed-atc-64x32-miptree.dds  | Bin 0 -> 1504 bytes
>>   ...waffles-decompressed-rgb-64x32-miptree.dds | Bin 0 -> 11048 bytes
>>   tests/util/CMakeLists.txt                     |   1 +
>>   tests/util/piglit-dds.c                       | 211 ++++++++++++++
>>   tests/util/piglit-dds.h                       |  72 +++++
>>   9 files changed, 556 insertions(+)
>>   create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
>>   create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.txt
>>   create mode 100644 tests/spec/amd_compressed_atc_texture/miptree.c
>>   create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
>>   create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
>>   create mode 100644 tests/util/piglit-dds.c
>>   create mode 100644 tests/util/piglit-dds.h
>>
>> diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
>> index 7f0d3a44e..6169041ff 100644
>> --- a/tests/spec/CMakeLists.txt
>> +++ b/tests/spec/CMakeLists.txt
>> @@ -1,5 +1,6 @@
>>   add_subdirectory (amd_framebuffer_multisample_advanced)
>>   add_subdirectory (amd_depth_clamp_separate)
>> +add_subdirectory (amd_compressed_atc_texture)
>>   add_subdirectory (amd_performance_monitor)
>>   add_subdirectory (amd_pinned_memory)
>>   add_subdirectory (arb_arrays_of_arrays)
>> diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
>> new file mode 100644
>> index 000000000..0509e44ae
>> --- /dev/null
>> +++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
>> @@ -0,0 +1,6 @@
>> +include_directories(
>> +       ${GLEXT_INCLUDE_DIR}
>> +       ${OPENGL_INCLUDE_PATH}
>> +)
>> +link_libraries(piglitutil_${piglit_target_api})
>> +piglit_add_executable(amd_compressed_atc_texture-miptree miptree.c)
>> diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
>> new file mode 100644
>> index 000000000..144a306f4
>> --- /dev/null
>> +++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
>> @@ -0,0 +1 @@
>> +piglit_include_target_api()
>> diff --git a/tests/spec/amd_compressed_atc_texture/miptree.c b/tests/spec/amd_compressed_atc_texture/miptree.c
>> new file mode 100644
>> index 000000000..5a2cb044a
>> --- /dev/null
>> +++ b/tests/spec/amd_compressed_atc_texture/miptree.c
>> @@ -0,0 +1,264 @@
>> +/*
>> + * Copyright 2012 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
>> + * \brief Test texturing from an ATC miptree of a real image.
>> + *
>> + * Copied from identical ETC1 test.
>> + *
>> + * This test uses two data files. The file waffles-compressed-atc-64x32.dds
>> + * contains a full miptree in GL_ATC_RGB_AMD format of a 2D texture of
>> + * waffles and fruit [1].  The base level size is 64x32 pixels. The file
>> + * waffles-decompressed-rgb-64x32.dds contains a parallel miptree in GL_RGBA
>> + * format. Each of its RGB images was obtained by decompressing the corresponding
>> + * ATC image with AMD-supplied Compressonator [2].
>> + *
>> + * This test draws each miplevel i of the ATC texture such that the image's
>> + * lower left corner is at (x=0, y=sum(height of miplevel j for j=0 to i-1)),
>> + * and it draws each miplevel of the RGB texture to the right of its
>> + * corresponding ETC1 image. Then it compares that the images are identical.
>> + *
>> + * [1] The reference image is located at http://people.freedesktop.org/~chadversary/permalink/2012-07-09/1574cff2-d091-4421-a3cf-b56c7943d060.jpg.
>> + * [2] https://github.com/GPUOpen-Tools/Compressonator
>> + */
>> +
>> +#include "piglit-util-gl.h"
>> +#include "piglit-dds.h"
>> +
>> +/* note: open Compressonator tool is buggy and fails to generate the 7th 1x1 level */
>> +#define num_levels 6
>> +#define level0_width 64
>> +#define level0_height 32
>> +
>> +#define num_vertices 4
>> +
>> +static const int window_width = 2 * level0_width;
>> +static const int window_height = 2 * level0_height;
>> +
>> +PIGLIT_GL_TEST_CONFIG_BEGIN
>> +
>> +       config.supports_gl_es_version = 20;
>> +
>> +       config.window_width = window_width;
>> +       config.window_height = window_height;
>> +       config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
>> +
>> +PIGLIT_GL_TEST_CONFIG_END
>> +
>> +
>> +static GLuint prog;
>> +
>> +/* Texture objects. */
>> +static GLuint compressed_tex;
>> +static GLuint decompressed_tex;
>> +
>> +/**
>> + * The \a filename is relative to the current test's source directory.
>> + *
>> + * A new texture is created and returned in \a tex_name.
>> + */
>> +static void
>> +load_texture(const char *filename, GLuint *tex_name)
>> +{
>> +       struct piglit_dds *dds;
>> +       const struct piglit_dds_info *info;
>> +       char filepath[4096];
>> +       int i;
>> +
>> +       piglit_join_paths(filepath, sizeof(filepath), 5,
>> +                         piglit_source_dir(),
>> +                         "tests",
>> +                         "spec",
>> +                         "amd_compressed_atc_texture",
>> +                         filename);
>> +
>> +       dds = piglit_dds_read_file(filepath);
>> +       if (dds == NULL)
>> +               piglit_report_result(PIGLIT_FAIL);
>> +
>> +       info = piglit_dds_get_info(dds);
>> +       assert(info->num_miplevels >= num_levels);
>> +       assert(info->pixel_width == level0_width);
>> +       assert(info->pixel_height== level0_height);
>> +
>> +       glGenTextures(1, tex_name);
>> +       glBindTexture(GL_TEXTURE_2D, *tex_name);
>> +       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
>> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_levels - 1);
>> +
>> +       for (i = 0; i < num_levels; i++) {
>> +               const struct piglit_dds_image *img = piglit_dds_get_image(dds, i);
>> +               if (info->gl_internal_format == GL_RGBA)
>> +                       glTexImage2D(GL_TEXTURE_2D, i,
>> +                                    info->gl_internal_format,
>> +                                    img->pixel_width,
>> +                                    img->pixel_height,
>> +                                    0,
>> +                                    GL_RGBA, GL_UNSIGNED_BYTE,
>> +                                    img->data);
>> +               else
>> +                       glCompressedTexImage2D(GL_TEXTURE_2D, i,
>> +                                              info->gl_internal_format,
>> +                                              img->pixel_width,
>> +                                              img->pixel_height,
>> +                                              0,
>> +                                              img->size,
>> +                                              img->data);
>> +               if (glGetError())
>> +                       piglit_report_result(PIGLIT_FAIL);
>> +       }
>> +
>> +       piglit_dds_destroy(dds);
>> +}
>> +
>> +void
>> +piglit_init(int argc, char **argv)
>> +{
>> +       static const char compressed_filename[] = "waffles-compressed-atc-64x32-miptree.dds";
>> +       static const char decompressed_filename[] = "waffles-decompressed-rgb-64x32-miptree.dds";
>> +
>> +       const char vs_source[] =
>> +               "#version 100\n"
>> +               "\n"
>> +               "uniform vec2 window_pixel_size;\n"
>> +               "uniform vec2 level_pixel_size;\n"
>> +               "uniform vec2 pixel_offset;\n"
>> +               "\n"
>> +               "// vertex is some corner of the unit square [0,1]^2 \n"
>> +               "attribute vec2 vertex;\n"
>> +               "varying vec2 tex_coord;\n"
>> +               "\n"
>> +               "void main()\n"
>> +               "{\n"
>> +               "    vec2 pos = vertex;\n"
>> +               "    pos *= level_pixel_size;\n"
>> +               "    pos += pixel_offset;\n"
>> +               "    pos /= 0.5 * window_pixel_size;\n"
>> +               "    pos -= vec2(1, 1);\n"
>> +               "    gl_Position = vec4(pos.xy, 0.0, 1.0);\n"
>> +               "\n"
>> +               "    tex_coord = vertex;\n"
>> +               "}\n";
>> +
>> +       const char fs_source[] =
>> +               "#version 100\n"
>> +               "precision highp float;\n"
>> +               "\n"
>> +               "uniform sampler2D tex;\n"
>> +               "varying vec2 tex_coord;\n"
>> +               "\n"
>> +               "void main()\n"
>> +               "{\n"
>> +               "    vec4 t = texture2D(tex, tex_coord);\n"
>> +               "    gl_FragColor = vec4(t.rgb, 1.0);\n"
>> +               "}\n";
>> +
>> +       /* Draw a square triangle strip. */
>> +       const GLfloat vertices[2 * num_vertices] = {
>> +               0, 0,
>> +               1, 0,
>> +               1, 1,
>> +               0, 1,
>> +       };
>> +
>> +       GLint vertex_loc;
>> +       GLuint vertex_buf;
>> +
>> +       piglit_require_extension("GL_AMD_compressed_ATC_texture");
>> +
>> +       load_texture(compressed_filename, &compressed_tex);
>> +       load_texture(decompressed_filename, &decompressed_tex);
>> +
>> +       glClearColor(1.0, 0.0, 0.0, 1.0);
>> +       glViewport(0, 0, window_width, window_height);
>> +
>> +       prog = piglit_build_simple_program(vs_source, fs_source);
>> +       glUseProgram(prog);
>> +
>> +       vertex_loc = glGetAttribLocation(prog, "vertex");
>> +       glGenBuffers(1, &vertex_buf);
>> +       glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
>> +       glEnableVertexAttribArray(vertex_loc);
>> +       glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
>> +       glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
>> +                    GL_STATIC_DRAW);
>> +
>> +       glUniform1i(glGetUniformLocation(prog, "tex"), 0);
>> +       glActiveTexture(GL_TEXTURE0);
>> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
>> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
>> +
>> +       glUniform2f(glGetUniformLocation(prog, "window_pixel_size"),
>> +                   window_width, window_height);
>> +}
>> +
>> +static void
>> +minify(int *x)
>> +{
>> +       assert(*x > 0);
>> +
>> +       if (*x > 1)
>> +               *x >>= 1;
>> +}
>> +
>> +enum piglit_result
>> +piglit_display(void)
>> +{
>> +       GLint pixel_offset_loc = glGetUniformLocation(prog, "pixel_offset");
>> +       GLint level_pixel_size_loc = glGetUniformLocation(prog, "level_pixel_size");
>> +
>> +       int level = 0;
>> +       int level_width = level0_width;
>> +       int level_height = level0_height;
>> +       int y_offset = 0;
>> +
>> +       bool pass = true;
>> +
>> +       glClear(GL_COLOR_BUFFER_BIT);
>> +
>> +       for (level = 0; level < num_levels; ++level) {
>> +               glUniform2f(level_pixel_size_loc,
>> +                           (float) level_width,
>> +                           (float) level_height);
>> +
>> +               /* Draw miplevel of compressed texture. */
>> +               glBindTexture(GL_TEXTURE_2D, compressed_tex);
>> +               glUniform2f(pixel_offset_loc, 0, y_offset);
>> +               glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
>> +
>> +               /* Draw miplevel of decompressed texture. */
>> +               glBindTexture(GL_TEXTURE_2D, decompressed_tex);
>> +               glUniform2f(pixel_offset_loc, level0_width, y_offset);
>> +               glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
>> +
>> +               y_offset += level_height;
>> +               minify(&level_width);
>> +               minify(&level_height);
>> +       }
>> +
>> +       pass = piglit_probe_rect_halves_equal_rgba(0, 0, window_width, window_height);
>> +       piglit_present_results();
>> +
>> +       return pass ? PIGLIT_PASS : PIGLIT_FAIL;
>> +}
>> diff --git a/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..495e565b9ad0c535366c3fdbf92375e54574530f
>> GIT binary patch
>> literal 1504
>> zcma)6Z%k8H6u(bxtF1}9g%KDf(g_Ql-D(zCFqz|(g03=?;;0J{oKnHiPU_rZ)G9^n
>> zHqDG<nYu3qWl{}7QsZ#hAEYQa0@I{!)c9fc73rf;MeFunZ^6EIb_;PI=9k^%-rv3V
>> z+<SgEzjMwlEqy=d076KnlA|1gH0fwbYCuT30RMZ;AtxoI8!C;d>2qzVihgd7aWb$s
>> zDF}=c09gWoc@zScc?5tIRuT*nycmUdtQNBH)kv*r?btz4w6@THZ$L@U$(#Ym%0#Fx
>> zXE-iZ)PPZUXRKwH3K`Ww03ne87r6((AvBNkev8R8#m~ifK!}+){1;RA$fH-=8-m!S
>> zS1Q(5dxKO($o#oslnwFcE!S%wiP6cENYgYd0!(+Z`%O@+%4<8EW12+B2KA<|;>l!}
>> zw0t*thbSbT@jt^qn&x@+rj#AB=p(kP7<>rrs5^~8K**@ukHJgP+ly3__L{ca_ls`y
>> zLKl^OD0iY8T9HI!IvS@`R}-{lJ1+{{c<cU%Fx&4)kL)o6>P%cU)|T_sPk<Zu^y35<
>> z4vR!b5EK8tqbJ^vyVIpotLk__RBdhhOf9_yLTtRF$URi7cVubQQ`cxD`PrI3!Ve6D
>> zPPprz#HE|co5Sz!;4)uSIy-ccUt*{{lQIlG3{TDeI9}@JeJ-iRP@#+W_k}&CJ$)FN
>> z{h?j1)7U?7s5KSGSwToH#3Py9zI^1SLZQeqF0VKiBSITh(VpwHnbYL1>y%NHOrzWJ
>> z+Z7M;51LtCWlli-#?hH%Y?1PnsuAviSJEk6^Kt}HJiE>i#0Ys{X&r;pR8)7qZ6Br)
>> z4PWm56LX0<xa?xUz%JxblIL-X-(oqKJ(z3ilQp2lt?E3xIS}%D3U^-NJeJD3j2lCW
>> z2T}HZk(*Bt#jZ7W3ceLmWZigy*NZ&zG(L%|kfPD^@m=f>vFu&vJv@sLpKt~-gp+X4
>> zP7r+G7nIaS&iuW1^oLFD_^H6WIj!y|`&no@BZz&Zz$OZ`L&YQ{=kkw+5d|=z8wppU
>> z8ki_J5^h1-ryco&VGzULPSn@)UWY<DvD!VRumhB>(FS@$K5tJ`5I8O=rs7&Div2sa
>> z#J^7|J+9pn8E<qOUem0N_#l0eJo{6(l0rzH{re|GX8)?}wGmW$lD}Bij%i8(w!(*F
>> zghz3tOiomS6B`<4`0i*Iy8pJERgevLm7GnA;GNp0j?m=(bX5?y_yyRI#}F&%htnAF
>> zIX0tTGv2Un`*0mB)4XtC#a2YgHQ%@iUre6ed+gF#TlCWF3`TTVEGS_x(RHD|1D3$E
>> zy0bT={JDxf>T0Z)ovgZPYK+G?V6D09<0T5EZ&|enVv-A`;#W*g#{MEYdp8@{3MYn_
>> z5VEe$eC(iUx+8xXUoElwzAIQV!#^6ky|QA82YC9mtmy;n9}5ffbwK_d>+<1qhZonJ
>> zvgUlzla|pOt)tz1X-M?CYag;7Q5$++HSEJ^W>zrSNPe9Hh}Q-2X)$V^Rx^a%K@IB6
>> z0r_0iyRuNuqHdTonq;il8v)stW|EIBoL$R+DEbuTdCiZ{Y)a{$&8(p4%2k^7$Eb}L
>> zFPKt(x>2ry0ey``b)#r~JiB?e)3%!=T{6K9<@O9w9d=;r-?~F|43y{fVT<UHt<sSH
>> lp{XQ%z9I-N38F{K0LI6<N+MNvCx_1tpM7u3<y$vN`v-g6D{TM(
>>
>> literal 0
>> HcmV?d00001
>>
>> diff --git a/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..a5b47df2b828feef99e283be042a24631e422098
>> GIT binary patch
>> literal 11048
>> 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
>> C>eV{{
>>
>> literal 0
>> HcmV?d00001
>>
>> diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt
>> index a5f080156..f6a2b69a9 100644
>> --- a/tests/util/CMakeLists.txt
>> +++ b/tests/util/CMakeLists.txt
>> @@ -48,6 +48,7 @@ set(UTIL_GL_INCLUDES
>>   set(UTIL_GL_SOURCES
>>          fdo-bitmap.c
>>          minmax-test.c
>> +       piglit-dds.c
>>          piglit-dispatch.c
>>          piglit-dispatch-init.c
>>          piglit-fbo.cpp
>> diff --git a/tests/util/piglit-dds.c b/tests/util/piglit-dds.c
>> new file mode 100644
>> index 000000000..2ab6e6af5
>> --- /dev/null
>> +++ b/tests/util/piglit-dds.c
>> @@ -0,0 +1,211 @@
>> +#include <assert.h>
>> +#include <stdarg.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +
>> +#include "piglit-dds.h"
>> +#include "piglit-util-gl.h"
>> +
>> +
>> +// DDS values taken from http://www.mindcontrol.org/~hplus/graphics/dds-info/
>> +
>> +//  little-endian, of course
>> +
>> +//  DDS_header.dwFlags
>> +#define DDSD_CAPS                   0x00000001
>> +#define DDSD_HEIGHT                 0x00000002
>> +#define DDSD_WIDTH                  0x00000004
>> +#define DDSD_PITCH                  0x00000008
>> +#define DDSD_PIXELFORMAT            0x00001000
>> +#define DDSD_MIPMAPCOUNT            0x00020000
>> +#define DDSD_LINEARSIZE             0x00080000
>> +#define DDSD_DEPTH                  0x00800000
>> +
>> +//  DDS_header.sPixelFormat.dwFlags
>> +#define DDPF_ALPHAPIXELS            0x00000001
>> +#define DDPF_FOURCC                 0x00000004
>> +#define DDPF_INDEXED                0x00000020
>> +#define DDPF_RGB                    0x00000040
>> +
>> +//  DDS_header.sCaps.dwCaps1
>> +#define DDSCAPS_COMPLEX             0x00000008
>> +#define DDSCAPS_TEXTURE             0x00001000
>> +#define DDSCAPS_MIPMAP              0x00400000
>> +
>> +//  DDS_header.sCaps.dwCaps2
>> +#define DDSCAPS2_CUBEMAP            0x00000200
>> +#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
>> +#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
>> +#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
>> +#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
>> +#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
>> +#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
>> +#define DDSCAPS2_VOLUME             0x00200000
>> +
>> +union DDS_header {
>> +       struct {
>> +               unsigned int    dwMagic;
>> +               unsigned int    dwSize;
>> +               unsigned int    dwFlags;
>> +               unsigned int    dwHeight;
>> +               unsigned int    dwWidth;
>> +               unsigned int    dwPitchOrLinearSize;
>> +               unsigned int    dwDepth;
>> +               unsigned int    dwMipMapCount;
>> +               unsigned int    dwReserved1[ 11 ];
>> +
>> +               //  DDPIXELFORMAT
>> +               struct {
>> +                       unsigned int    dwSize;
>> +                       unsigned int    dwFlags;
>> +                       unsigned int    dwFourCC;
>> +                       unsigned int    dwRGBBitCount;
>> +                       unsigned int    dwRBitMask;
>> +                       unsigned int    dwGBitMask;
>> +                       unsigned int    dwBBitMask;
>> +                       unsigned int    dwAlphaBitMask;
>> +               }               sPixelFormat;
>> +
>> +               //  DDCAPS2
>> +               struct {
>> +                       unsigned int    dwCaps1;
>> +                       unsigned int    dwCaps2;
>> +                       unsigned int    dwDDSX;
>> +                       unsigned int    dwReserved;
>> +               }               sCaps;
>> +               unsigned int    dwReserved2;
>> +       };
>> +       char data[ 128 ];
>> +};
>> +
>> +#define FOURCC(a, b, c, d)  ((a) << 0 | (b) << 8 | (c) << 16 | (d) << 24)
>> +
>> +#define DDS_MAGIC   FOURCC('D', 'D', 'S', ' ')
>> +#define ATC_RGB     FOURCC('A', 'T', 'C', ' ')
>> +#define ATC_RGBA_E  FOURCC('A', 'T', 'C', 'A')
>> +#define ATC_RGBA_I  FOURCC('A', 'T', 'C', 'I')
>> +
>> +struct piglit_dds {
>> +       struct piglit_dds_info info;
>> +       uint8_t *data;
>> +       size_t size;
>> +
>> +       struct piglit_dds_image *images;
>> +};
>> +
>> +void
>> +piglit_dds_destroy(struct piglit_dds *self)
>> +{
>> +       free(self->images);
>> +       free(self->data);
>> +       free(self);
>> +}
>> +
>> +struct piglit_dds *
>> +piglit_dds_read_file(const char *filename)
>> +{
>> +       struct piglit_dds *ret = calloc(1, sizeof(struct piglit_dds));
>> +       FILE *f;
>> +       bool success = false;
>> +       int read, i, shift = 0, factor = 0;
>> +       union DDS_header *header;
>> +
>> +       if (!ret)
>> +               goto err_ret;
>> +
>> +       f = fopen(filename, "rb");
>> +
>> +       if (!f)
>> +               goto err_file;
>> +
>> +       if (fseek(f, 0, SEEK_END))
>> +               goto err_read;
>> +       ret->size = ftell(f);
>> +       if (fseek(f, 0, SEEK_SET))
>> +               goto err_read;
>> +
>> +       ret->data = malloc(ret->size);
>> +       if (!ret->data)
>> +               goto err_read;
>> +
>> +       read = fread(ret->data, 1, ret->size, f);
>> +       if (read < ret->size)
>> +               goto err_read;
>> +
>> +       header = (union DDS_header*) ret->data;
>> +
>> +       if (header->dwMagic != DDS_MAGIC)
>> +               goto err_read;
>> +
>> +       ret->info.num_miplevels = header->dwMipMapCount;
>> +       ret->info.pixel_width = header->dwWidth;
>> +       ret->info.pixel_height = header->dwHeight;
>> +       switch (header->sPixelFormat.dwFourCC) {
>> +       case 0:
>> +               ret->info.gl_internal_format = GL_RGBA;
>> +               factor = 4;
>> +               break;
>> +       case ATC_RGB:
>> +               ret->info.gl_internal_format = GL_ATC_RGB_AMD;
>> +               shift = 1;
>> +               break;
>> +       case ATC_RGBA_I:
>> +               ret->info.gl_internal_format = GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
>> +               break;
>> +       case ATC_RGBA_E:
>> +               ret->info.gl_internal_format = GL_ATC_RGBA_EXPLICIT_ALPHA_AMD;
>> +               break;
>> +       default:
>> +               goto err_read;
>> +       }
>> +
>> +       ret->images = calloc(ret->info.num_miplevels, sizeof(struct piglit_dds_image));
>> +       for (i = 0; i < ret->info.num_miplevels; i++) {
>> +               struct piglit_dds_image *img = &ret->images[i];
>> +               if (i == 0) {
>> +                       img->data = ret->data + 128;
>> +                       img->pixel_width = ret->info.pixel_width;
>> +                       img->pixel_height = ret->info.pixel_height;
>> +               } else {
>> +                       struct piglit_dds_image *prev = &ret->images[i - 1];
>> +                       img->data = prev->data + prev->size;
>> +                       img->pixel_width = MAX2(1, prev->pixel_width >> 1);
>> +                       img->pixel_height = MAX2(1, prev->pixel_height >> 1);
>> +               }
>> +               if (header->sPixelFormat.dwFourCC)
>> +                       img->size = ALIGN(img->pixel_width, 4) * ALIGN(img->pixel_height, 4);
>> +               else
>> +                       img->size = img->pixel_width * img->pixel_height;
>> +               if (shift > 0)
>> +                       img->size >>= shift;
>> +               if (factor > 0)
>> +                       img->size *= factor;
>> +       }
>> +
>> +       success = true;
>> +
>> +err_read:
>> +       fclose(f);
>> +       if (success)
>> +               return ret;
>> +       if (ret->data)
>> +               free(ret->data);
>> +err_file:
>> +       free(ret);
>> +err_ret:
>> +       return NULL;
>> +}
>> +
>> +const struct piglit_dds_info *
>> +piglit_dds_get_info(struct piglit_dds *self)
>> +{
>> +       return &self->info;
>> +}
>> +
>> +const struct piglit_dds_image *
>> +piglit_dds_get_image(struct piglit_dds *self,
>> +                     int miplevel)
>> +{
>> +       assert(miplevel < self->info.num_miplevels);
>> +       return &self->images[miplevel];
>> +}
>> diff --git a/tests/util/piglit-dds.h b/tests/util/piglit-dds.h
>> new file mode 100644
>> index 000000000..28660b99d
>> --- /dev/null
>> +++ b/tests/util/piglit-dds.h
>> @@ -0,0 +1,72 @@
>> +/*
>> + * Copyright 2015 Ilia Mirkin
>> + *
>> + * 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
>> + *
>> + * \brief Utilities for the DDS file format
>> + *
>> + * The DDS file format specifies a simple format for storing texture
>> + * miptrees.
>> + */
>> +
>> +#include <stdint.h>
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif
>> +
>> +struct piglit_dds;
>> +
>> +struct piglit_dds_info {
>> +  uint32_t gl_internal_format;
>> +  uint32_t num_miplevels;
>> +
>> +  uint32_t pixel_width;
>> +  uint32_t pixel_height;
>> +};
>> +
>> +struct piglit_dds_image {
>> +  const uint8_t *data;
>> +  size_t size;
>> +
>> +  uint32_t pixel_width;
>> +  uint32_t pixel_height;
>> +};
>> +
>> +void
>> +piglit_dds_destroy(struct piglit_dds *self);
>> +
>> +struct piglit_dds *
>> +piglit_dds_read_file(const char *filename);
>> +
>> +const struct piglit_dds_info *
>> +piglit_dds_get_info(struct piglit_dds *self);
>> +
>> +const struct piglit_dds_image *
>> +piglit_dds_get_image(struct piglit_dds *self,
>> +                     int miplevel);
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif
>> --
>> 2.17.1
>>
Oh right, yeah. ETC. Not ASTC. And yes, it's very explicitly in there.
I managed to glaze over that. Go me...

On Tue, Apr 9, 2019 at 4:21 PM Jonathan Marek <jonathan@marek.ca> wrote:
>
> Yes, the tool supports KTX. I made a new version of the patch with a new
> copy of the ETC1 test which uses KTX and dropped the DDS loader.
>
> The comment after the copyright header says it is copied from ETC1
> miptree test, so I guess its already OK?
>
> On 4/9/19 12:48 PM, Ilia Mirkin wrote:
> > Back when I did this, DDS was the only output format supported by the
> > tool I was using, and while I thought about converting to KTX "by
> > hand", that seemed sufficiently unpleasant (I don't remember all the
> > details, TBH -- it's been 4 years, seemingly). Does the new tool
> > support KTX output, or still just DDS only? If it supports KTX,
> > there's existing infra in piglit to process it.
> >
> > Also, for the miptree.c header - can you include a mention that it was
> > based on the miptree.c from the ASTC tests? Otherwise the Intel
> > copyright is fairly unclear.
> >
> > On Tue, Apr 9, 2019 at 10:58 AM Jonathan Marek <jonathan@marek.ca> wrote:
> >>
> >> From: Ilia Mirkin <imirkin@alum.mit.edu>
> >>
> >> This echoes the ETC1 miptree test, and even uses the same image.
> >>
> >> Updated to work with images created with the open source tool.
> >>
> >> Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
> >> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
> >> ---
> >>   tests/spec/CMakeLists.txt                     |   1 +
> >>   .../CMakeLists.gles2.txt                      |   6 +
> >>   .../amd_compressed_atc_texture/CMakeLists.txt |   1 +
> >>   .../spec/amd_compressed_atc_texture/miptree.c | 264 ++++++++++++++++++
> >>   .../waffles-compressed-atc-64x32-miptree.dds  | Bin 0 -> 1504 bytes
> >>   ...waffles-decompressed-rgb-64x32-miptree.dds | Bin 0 -> 11048 bytes
> >>   tests/util/CMakeLists.txt                     |   1 +
> >>   tests/util/piglit-dds.c                       | 211 ++++++++++++++
> >>   tests/util/piglit-dds.h                       |  72 +++++
> >>   9 files changed, 556 insertions(+)
> >>   create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
> >>   create mode 100644 tests/spec/amd_compressed_atc_texture/CMakeLists.txt
> >>   create mode 100644 tests/spec/amd_compressed_atc_texture/miptree.c
> >>   create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
> >>   create mode 100644 tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
> >>   create mode 100644 tests/util/piglit-dds.c
> >>   create mode 100644 tests/util/piglit-dds.h
> >>
> >> diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
> >> index 7f0d3a44e..6169041ff 100644
> >> --- a/tests/spec/CMakeLists.txt
> >> +++ b/tests/spec/CMakeLists.txt
> >> @@ -1,5 +1,6 @@
> >>   add_subdirectory (amd_framebuffer_multisample_advanced)
> >>   add_subdirectory (amd_depth_clamp_separate)
> >> +add_subdirectory (amd_compressed_atc_texture)
> >>   add_subdirectory (amd_performance_monitor)
> >>   add_subdirectory (amd_pinned_memory)
> >>   add_subdirectory (arb_arrays_of_arrays)
> >> diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
> >> new file mode 100644
> >> index 000000000..0509e44ae
> >> --- /dev/null
> >> +++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.gles2.txt
> >> @@ -0,0 +1,6 @@
> >> +include_directories(
> >> +       ${GLEXT_INCLUDE_DIR}
> >> +       ${OPENGL_INCLUDE_PATH}
> >> +)
> >> +link_libraries(piglitutil_${piglit_target_api})
> >> +piglit_add_executable(amd_compressed_atc_texture-miptree miptree.c)
> >> diff --git a/tests/spec/amd_compressed_atc_texture/CMakeLists.txt b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
> >> new file mode 100644
> >> index 000000000..144a306f4
> >> --- /dev/null
> >> +++ b/tests/spec/amd_compressed_atc_texture/CMakeLists.txt
> >> @@ -0,0 +1 @@
> >> +piglit_include_target_api()
> >> diff --git a/tests/spec/amd_compressed_atc_texture/miptree.c b/tests/spec/amd_compressed_atc_texture/miptree.c
> >> new file mode 100644
> >> index 000000000..5a2cb044a
> >> --- /dev/null
> >> +++ b/tests/spec/amd_compressed_atc_texture/miptree.c
> >> @@ -0,0 +1,264 @@
> >> +/*
> >> + * Copyright 2012 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
> >> + * \brief Test texturing from an ATC miptree of a real image.
> >> + *
> >> + * Copied from identical ETC1 test.
> >> + *
> >> + * This test uses two data files. The file waffles-compressed-atc-64x32.dds
> >> + * contains a full miptree in GL_ATC_RGB_AMD format of a 2D texture of
> >> + * waffles and fruit [1].  The base level size is 64x32 pixels. The file
> >> + * waffles-decompressed-rgb-64x32.dds contains a parallel miptree in GL_RGBA
> >> + * format. Each of its RGB images was obtained by decompressing the corresponding
> >> + * ATC image with AMD-supplied Compressonator [2].
> >> + *
> >> + * This test draws each miplevel i of the ATC texture such that the image's
> >> + * lower left corner is at (x=0, y=sum(height of miplevel j for j=0 to i-1)),
> >> + * and it draws each miplevel of the RGB texture to the right of its
> >> + * corresponding ETC1 image. Then it compares that the images are identical.
> >> + *
> >> + * [1] The reference image is located at http://people.freedesktop.org/~chadversary/permalink/2012-07-09/1574cff2-d091-4421-a3cf-b56c7943d060.jpg.
> >> + * [2] https://github.com/GPUOpen-Tools/Compressonator
> >> + */
> >> +
> >> +#include "piglit-util-gl.h"
> >> +#include "piglit-dds.h"
> >> +
> >> +/* note: open Compressonator tool is buggy and fails to generate the 7th 1x1 level */
> >> +#define num_levels 6
> >> +#define level0_width 64
> >> +#define level0_height 32
> >> +
> >> +#define num_vertices 4
> >> +
> >> +static const int window_width = 2 * level0_width;
> >> +static const int window_height = 2 * level0_height;
> >> +
> >> +PIGLIT_GL_TEST_CONFIG_BEGIN
> >> +
> >> +       config.supports_gl_es_version = 20;
> >> +
> >> +       config.window_width = window_width;
> >> +       config.window_height = window_height;
> >> +       config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
> >> +
> >> +PIGLIT_GL_TEST_CONFIG_END
> >> +
> >> +
> >> +static GLuint prog;
> >> +
> >> +/* Texture objects. */
> >> +static GLuint compressed_tex;
> >> +static GLuint decompressed_tex;
> >> +
> >> +/**
> >> + * The \a filename is relative to the current test's source directory.
> >> + *
> >> + * A new texture is created and returned in \a tex_name.
> >> + */
> >> +static void
> >> +load_texture(const char *filename, GLuint *tex_name)
> >> +{
> >> +       struct piglit_dds *dds;
> >> +       const struct piglit_dds_info *info;
> >> +       char filepath[4096];
> >> +       int i;
> >> +
> >> +       piglit_join_paths(filepath, sizeof(filepath), 5,
> >> +                         piglit_source_dir(),
> >> +                         "tests",
> >> +                         "spec",
> >> +                         "amd_compressed_atc_texture",
> >> +                         filename);
> >> +
> >> +       dds = piglit_dds_read_file(filepath);
> >> +       if (dds == NULL)
> >> +               piglit_report_result(PIGLIT_FAIL);
> >> +
> >> +       info = piglit_dds_get_info(dds);
> >> +       assert(info->num_miplevels >= num_levels);
> >> +       assert(info->pixel_width == level0_width);
> >> +       assert(info->pixel_height== level0_height);
> >> +
> >> +       glGenTextures(1, tex_name);
> >> +       glBindTexture(GL_TEXTURE_2D, *tex_name);
> >> +       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
> >> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_levels - 1);
> >> +
> >> +       for (i = 0; i < num_levels; i++) {
> >> +               const struct piglit_dds_image *img = piglit_dds_get_image(dds, i);
> >> +               if (info->gl_internal_format == GL_RGBA)
> >> +                       glTexImage2D(GL_TEXTURE_2D, i,
> >> +                                    info->gl_internal_format,
> >> +                                    img->pixel_width,
> >> +                                    img->pixel_height,
> >> +                                    0,
> >> +                                    GL_RGBA, GL_UNSIGNED_BYTE,
> >> +                                    img->data);
> >> +               else
> >> +                       glCompressedTexImage2D(GL_TEXTURE_2D, i,
> >> +                                              info->gl_internal_format,
> >> +                                              img->pixel_width,
> >> +                                              img->pixel_height,
> >> +                                              0,
> >> +                                              img->size,
> >> +                                              img->data);
> >> +               if (glGetError())
> >> +                       piglit_report_result(PIGLIT_FAIL);
> >> +       }
> >> +
> >> +       piglit_dds_destroy(dds);
> >> +}
> >> +
> >> +void
> >> +piglit_init(int argc, char **argv)
> >> +{
> >> +       static const char compressed_filename[] = "waffles-compressed-atc-64x32-miptree.dds";
> >> +       static const char decompressed_filename[] = "waffles-decompressed-rgb-64x32-miptree.dds";
> >> +
> >> +       const char vs_source[] =
> >> +               "#version 100\n"
> >> +               "\n"
> >> +               "uniform vec2 window_pixel_size;\n"
> >> +               "uniform vec2 level_pixel_size;\n"
> >> +               "uniform vec2 pixel_offset;\n"
> >> +               "\n"
> >> +               "// vertex is some corner of the unit square [0,1]^2 \n"
> >> +               "attribute vec2 vertex;\n"
> >> +               "varying vec2 tex_coord;\n"
> >> +               "\n"
> >> +               "void main()\n"
> >> +               "{\n"
> >> +               "    vec2 pos = vertex;\n"
> >> +               "    pos *= level_pixel_size;\n"
> >> +               "    pos += pixel_offset;\n"
> >> +               "    pos /= 0.5 * window_pixel_size;\n"
> >> +               "    pos -= vec2(1, 1);\n"
> >> +               "    gl_Position = vec4(pos.xy, 0.0, 1.0);\n"
> >> +               "\n"
> >> +               "    tex_coord = vertex;\n"
> >> +               "}\n";
> >> +
> >> +       const char fs_source[] =
> >> +               "#version 100\n"
> >> +               "precision highp float;\n"
> >> +               "\n"
> >> +               "uniform sampler2D tex;\n"
> >> +               "varying vec2 tex_coord;\n"
> >> +               "\n"
> >> +               "void main()\n"
> >> +               "{\n"
> >> +               "    vec4 t = texture2D(tex, tex_coord);\n"
> >> +               "    gl_FragColor = vec4(t.rgb, 1.0);\n"
> >> +               "}\n";
> >> +
> >> +       /* Draw a square triangle strip. */
> >> +       const GLfloat vertices[2 * num_vertices] = {
> >> +               0, 0,
> >> +               1, 0,
> >> +               1, 1,
> >> +               0, 1,
> >> +       };
> >> +
> >> +       GLint vertex_loc;
> >> +       GLuint vertex_buf;
> >> +
> >> +       piglit_require_extension("GL_AMD_compressed_ATC_texture");
> >> +
> >> +       load_texture(compressed_filename, &compressed_tex);
> >> +       load_texture(decompressed_filename, &decompressed_tex);
> >> +
> >> +       glClearColor(1.0, 0.0, 0.0, 1.0);
> >> +       glViewport(0, 0, window_width, window_height);
> >> +
> >> +       prog = piglit_build_simple_program(vs_source, fs_source);
> >> +       glUseProgram(prog);
> >> +
> >> +       vertex_loc = glGetAttribLocation(prog, "vertex");
> >> +       glGenBuffers(1, &vertex_buf);
> >> +       glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
> >> +       glEnableVertexAttribArray(vertex_loc);
> >> +       glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
> >> +       glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
> >> +                    GL_STATIC_DRAW);
> >> +
> >> +       glUniform1i(glGetUniformLocation(prog, "tex"), 0);
> >> +       glActiveTexture(GL_TEXTURE0);
> >> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
> >> +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
> >> +
> >> +       glUniform2f(glGetUniformLocation(prog, "window_pixel_size"),
> >> +                   window_width, window_height);
> >> +}
> >> +
> >> +static void
> >> +minify(int *x)
> >> +{
> >> +       assert(*x > 0);
> >> +
> >> +       if (*x > 1)
> >> +               *x >>= 1;
> >> +}
> >> +
> >> +enum piglit_result
> >> +piglit_display(void)
> >> +{
> >> +       GLint pixel_offset_loc = glGetUniformLocation(prog, "pixel_offset");
> >> +       GLint level_pixel_size_loc = glGetUniformLocation(prog, "level_pixel_size");
> >> +
> >> +       int level = 0;
> >> +       int level_width = level0_width;
> >> +       int level_height = level0_height;
> >> +       int y_offset = 0;
> >> +
> >> +       bool pass = true;
> >> +
> >> +       glClear(GL_COLOR_BUFFER_BIT);
> >> +
> >> +       for (level = 0; level < num_levels; ++level) {
> >> +               glUniform2f(level_pixel_size_loc,
> >> +                           (float) level_width,
> >> +                           (float) level_height);
> >> +
> >> +               /* Draw miplevel of compressed texture. */
> >> +               glBindTexture(GL_TEXTURE_2D, compressed_tex);
> >> +               glUniform2f(pixel_offset_loc, 0, y_offset);
> >> +               glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
> >> +
> >> +               /* Draw miplevel of decompressed texture. */
> >> +               glBindTexture(GL_TEXTURE_2D, decompressed_tex);
> >> +               glUniform2f(pixel_offset_loc, level0_width, y_offset);
> >> +               glDrawArrays(GL_TRIANGLE_FAN, 0, num_vertices);
> >> +
> >> +               y_offset += level_height;
> >> +               minify(&level_width);
> >> +               minify(&level_height);
> >> +       }
> >> +
> >> +       pass = piglit_probe_rect_halves_equal_rgba(0, 0, window_width, window_height);
> >> +       piglit_present_results();
> >> +
> >> +       return pass ? PIGLIT_PASS : PIGLIT_FAIL;
> >> +}
> >> diff --git a/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-compressed-atc-64x32-miptree.dds
> >> new file mode 100644
> >> index 0000000000000000000000000000000000000000..495e565b9ad0c535366c3fdbf92375e54574530f
> >> GIT binary patch
> >> literal 1504
> >> zcma)6Z%k8H6u(bxtF1}9g%KDf(g_Ql-D(zCFqz|(g03=?;;0J{oKnHiPU_rZ)G9^n
> >> zHqDG<nYu3qWl{}7QsZ#hAEYQa0@I{!)c9fc73rf;MeFunZ^6EIb_;PI=9k^%-rv3V
> >> z+<SgEzjMwlEqy=d076KnlA|1gH0fwbYCuT30RMZ;AtxoI8!C;d>2qzVihgd7aWb$s
> >> zDF}=c09gWoc@zScc?5tIRuT*nycmUdtQNBH)kv*r?btz4w6@THZ$L@U$(#Ym%0#Fx
> >> zXE-iZ)PPZUXRKwH3K`Ww03ne87r6((AvBNkev8R8#m~ifK!}+){1;RA$fH-=8-m!S
> >> zS1Q(5dxKO($o#oslnwFcE!S%wiP6cENYgYd0!(+Z`%O@+%4<8EW12+B2KA<|;>l!}
> >> zw0t*thbSbT@jt^qn&x@+rj#AB=p(kP7<>rrs5^~8K**@ukHJgP+ly3__L{ca_ls`y
> >> zLKl^OD0iY8T9HI!IvS@`R}-{lJ1+{{c<cU%Fx&4)kL)o6>P%cU)|T_sPk<Zu^y35<
> >> z4vR!b5EK8tqbJ^vyVIpotLk__RBdhhOf9_yLTtRF$URi7cVubQQ`cxD`PrI3!Ve6D
> >> zPPprz#HE|co5Sz!;4)uSIy-ccUt*{{lQIlG3{TDeI9}@JeJ-iRP@#+W_k}&CJ$)FN
> >> z{h?j1)7U?7s5KSGSwToH#3Py9zI^1SLZQeqF0VKiBSITh(VpwHnbYL1>y%NHOrzWJ
> >> z+Z7M;51LtCWlli-#?hH%Y?1PnsuAviSJEk6^Kt}HJiE>i#0Ys{X&r;pR8)7qZ6Br)
> >> z4PWm56LX0<xa?xUz%JxblIL-X-(oqKJ(z3ilQp2lt?E3xIS}%D3U^-NJeJD3j2lCW
> >> z2T}HZk(*Bt#jZ7W3ceLmWZigy*NZ&zG(L%|kfPD^@m=f>vFu&vJv@sLpKt~-gp+X4
> >> zP7r+G7nIaS&iuW1^oLFD_^H6WIj!y|`&no@BZz&Zz$OZ`L&YQ{=kkw+5d|=z8wppU
> >> z8ki_J5^h1-ryco&VGzULPSn@)UWY<DvD!VRumhB>(FS@$K5tJ`5I8O=rs7&Div2sa
> >> z#J^7|J+9pn8E<qOUem0N_#l0eJo{6(l0rzH{re|GX8)?}wGmW$lD}Bij%i8(w!(*F
> >> zghz3tOiomS6B`<4`0i*Iy8pJERgevLm7GnA;GNp0j?m=(bX5?y_yyRI#}F&%htnAF
> >> zIX0tTGv2Un`*0mB)4XtC#a2YgHQ%@iUre6ed+gF#TlCWF3`TTVEGS_x(RHD|1D3$E
> >> zy0bT={JDxf>T0Z)ovgZPYK+G?V6D09<0T5EZ&|enVv-A`;#W*g#{MEYdp8@{3MYn_
> >> z5VEe$eC(iUx+8xXUoElwzAIQV!#^6ky|QA82YC9mtmy;n9}5ffbwK_d>+<1qhZonJ
> >> zvgUlzla|pOt)tz1X-M?CYag;7Q5$++HSEJ^W>zrSNPe9Hh}Q-2X)$V^Rx^a%K@IB6
> >> z0r_0iyRuNuqHdTonq;il8v)stW|EIBoL$R+DEbuTdCiZ{Y)a{$&8(p4%2k^7$Eb}L
> >> zFPKt(x>2ry0ey``b)#r~JiB?e)3%!=T{6K9<@O9w9d=;r-?~F|43y{fVT<UHt<sSH
> >> lp{XQ%z9I-N38F{K0LI6<N+MNvCx_1tpM7u3<y$vN`v-g6D{TM(
> >>
> >> literal 0
> >> HcmV?d00001
> >>
> >> diff --git a/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds b/tests/spec/amd_compressed_atc_texture/waffles-decompressed-rgb-64x32-miptree.dds
> >> new file mode 100644
> >> index 0000000000000000000000000000000000000000..a5b47df2b828feef99e283be042a24631e422098
> >> GIT binary patch
> >> literal 11048
> >> zcmcJVe{fXQ701*5(a9ej8=a1<I11}f>@u-+Z5_G}PIc9aPwT*{l&+%H1&gdA%mM=h
> >> z1Y{8twxJ1YP{?47E*8uW4M`-BjZ$Rkn6iT48tM>#pxqf5XAvz=V>+kjd$Z^5eUBv}
> >> zcDnlEz72VM?&qBI-n;KDH{X2M*kvUpB|j?re#uxKZ(vHkhd)Y6elR$k_n%|=H*d`U
> >> zHnvMjNd8xEO3QA*XnUC^(ZDxE^es{U*F<<fQu_OO-#h~Y1Ej;BY<rnsngq7}<waUF
> >> zCrn|(u;|+r<#{yGKz0@NADu~N%11kDJhbM)G30lZDS~A#5?+3IDgQoCSjQG^=r`gC
> >> zcR@V#ap+I6|LsujAMN?8a`w1fB)}O+9^kF}n;#73!0Dga)J{*|6rk0!!{6B-Ge^zE
> >> zUG;!gOZE4T_xRaJU-0hPI9Gw1i#tZ~##p!D0abI<-6HRg9sp8%xMSPLv^Bg~$iWCF
> >> zHxhsJ#BeXvUtT6Rn7B6uT?BM@<f8S@a~0ADmbc`9{m}!0_{;de`r{aI=0NX<VYfv#
> >> zKbm|j3di1v(_2kbsXgwqh=#lb_B?kBWp@SWUmd@-pbsNN>}unrL6pZ#ddTl~*@y={
> >> zWFD@tu$>EVUKr+8>>Mzxvv$64e!RG6-|wPyebDkp9>BKM*DK&I{_kzRR^_0WKb%2-
> >> z`dT#(=YQr%SK(MV4}aAD|51Oq1F3yF`4IKJU!m%b9H9OH?gDz@#J16NIyqi}K7cnE
> >> zIC{PE-?nZd2`m0EfjZaTN{15nS)AGxACdovYOU8@wjB+C`b+I~e`o!r50a5G(&>wp
> >> z+H#=RA34bO7&hRJ9N;(r*?5p_J>Zz%S#QO|8tvCp)6DUDK;z3SU%xeS88S7pd!w}b
> >> z$@>*srvHZ8H+gI{E$8!~M(6Ue6gNsOK3Ml-GMn8N{mo-&pv^<n&F2Lsm$dV4<Z4O=
> >> zTo$={gT6Y_!E@&G5DxC)UY0liqS`*U|B2pa>g`%u)W2(UH39L5J6Jd45~^P~#$s*o
> >> zA~M{i3T%tJ<l*lNerUNP54t<H;s5XSJ@n1dKPuq=apjF<ZV##v{-?XEEPq~&4V{4^
> >> z{%1IUr*>6wFBz0c_-&->eWVi)Jz!mvaZQT2+zPm(58xm1m05_pjPN!O8;V2Ed#Nc<
> >> zLV6CQ?r=vhz#r~(lGln1ymiFi>H#u214HB>?|=HEqtw@4ubklxkb~j;<vNTJxqvrv
> >> zfDyfb+9L;&hsSTafPna;{_vI@z#Tb|<3POOZYIi9?Zq8=fIE6XaxhYV93#1=kVWm{
> >> zDU@lASfm@gq?4+3lMwNglCQMDW0zh=0bbJy<}S|Tt06j8a~q{YZbj$x33O=g)r2wb
> >> zb5oE%10<LG6j6UEHHI#r)RK!Rx5-6jE1wJUq@$y#ck>No?hh%jo#Q&`P#^aNGw|6q
> >> zb)5F|qD^0uIS&T7x6T`{;2R@y^Zdcgsn@A--qiA<{#)maBBwucA?_H(AMVHjfIGaM
> >> z{*njy!@Zb)+rt-9B2Ze?|8!@RfcRs?c^dvhy~H2xx<C2=Iq<nX3h4o<J^X8@Tu7)n
> >> zkUkLq&gB!8zxiQI^?>BStmd^WgB$?VedCPrss~m~9&M{V>W`YkJLW4@z<=-Z305CS
> >> z?cr{kSygw*LI24;-`OAT$N}n)9MsMKnd$@hi#zIH^V4!gYLZ`#@LzxT1O;+{{znb~
> >> z>JNAH07moxoZ*iVJs|amJ9+@_I&c?%z5l;D)TsR7tosjl4NPw`sPd8P$i?R@1)s-U
> >> zOsp!VSUh_Yx%oY4+7h5dm6sm<)hIH!*TI^rMk~^f`KaO6@s#ko6nke~uEu&^ljL}<
> >> zE0`RwZ`m&u*pB$UHlhK(KhQ`;{nY#F(+X^7Vg){VZ4qS?LHc}OHQ#ganuMV*dHtK?
> >> zH6Y;a@9K{n0CC57&n;Kk+;xArJN=OZ`0F`<vz~)3Ps|<GUvl8|M=s$1#Xno^{>Z_Z
> >> zj9Sm&_#f&VaIX40{o!8BKgd0xgZlSYUO{Fz-?uRD)cLI(AP)y-|3uMllo5bG$R5uq
> >> zT52i?^z3d_p!V<<ob`vh&EK(}IbZ+#CSPsqf88J6=>1~-FYY)Fa14mIjMDeg2XICX
> >> z<QNeD-CLhk{&N3V7>Pbj@3b&;X<lz@<on+0e}_NL{X^A1S!K||zyvb5Zoua*Q`~;t
> >> zB?Q7@4?PvVk=mQXiWINss~;IdUVa`2u(sP59c^8ssl!b|u6`7m9h?*9$cA$60~clZ
> >> z^S~!{cd9YV+u-vT_&oV-ip;OyBlDXNd7JM!6ouyrg`5<AmOYsxu&w1y+Oz*KU-L}r
> >> z?d?;ede)e~55Rdq!S`qKIgPCyR5N>`@|RJ(mHVtgclbXS4=BVRIl#88O=J}J&tex+
> >> zCQ_=rB?lPAUq<o&V&A$!f0J{dL;U_fy<`r2YRy~bj}h+CSVE21-n;)m!5z<9#XCR3
> >> zxnflnd3}aL>Mo<yfBNlXD6IJ-2LRqeF@Mxt+~ME7Y@EW%0bd7C?0DG91L_Wj^w(;p
> >> zyPr7qm2yYjr3d8svXuw+ZfWVDl`E^rmv<I-jOc%HclJO0rT@i$_T)<lNd5KRM-RYR
> >> z2R*NYzK1`+_F4Yue=tP<XZmn#m;`^g1L*<uexj*e^#DdV>*(&-PCZp1?Blh&$4-!c
> >> zRy|{a1%5}^Iqw?E@;XJwZ02Kv$!@wrk>T~y_Ia04i1!1LfQO!)e=TLU8uaQ@*Ha&_
> >> zzfZiq$$DnP9ZP)0vi@`SZ)M#}6bMDAW#>MwIro2-kN-T|8rvvZolyAv0V;|SB%g-v
> >> zkL}7S6KpwvzmB-e*z)*A=kz~TeL0Cga!?(-RQV$Za7PZD{?2<<-M_QzZv=n118j@C
> >> zjQ89>zqq&LgWZ=#Yg7&}I{mY?e9xxC>y_4p6Rr9`7rc^CcYquOc+FaQ*99bbklLp!
> >> zc<s)>-v&FwTd%+V%=TRVfnb;vTzkC-Q1cbhn8I(IqvqnyBb<dq<Ll?;pXD4_)cTcs
> >> zmPZBmKl}?hxPnmk;rvm5aQfIAR_`MZx<9s2^Y!uP2i-Xb;*Mhg+wh0CP_*aS`_5@|
> >> zD6%AOxl6yq!T}Q6wydYjmXM8X13#zMFuTK)ZGNx-|6TV|A64)=0JQVHuKxR}3SPVA
> >> zdADH&wO1GxeLWrdXKuVmajskVeRE42-E{M9<n?-K%G99Ru6Qy=;CI1?$nQ58cGnR9
> >> zSY3i1U9^UR;iwIqCwmSZ<MStf&&j}9{4q8~?;FxzcUQU4as%%pRlh!`Kk^{{2VUW4
> >> zbX@OZ-uM~Zmn>UNp;-|H@&E>%4VpD4lFvbLf4DpS<1gSoVbI$ed5w^Mv(w5!I2fP}
> >> zk?B?*^jc#3*o*fTYL7l}_&eWA?PU~ixsE&i#T)KG>W&`J{Ur~2?XfN17^gotU)3Jo
> >> zUHcB6?T%bvjiiD8M-LzmAQtjd^U}$Rx2o=-G_M17oWAlNeE`H8y`Mdfd(^`EQ?LK-
> >> z-Q8pa0_5@fY)JiOEc88kztI2D+Ij-IKaPQOdP^U03*r%x;H-!9y?K(K_cJXG&ydf<
> >> z-#J7=3iBPluVp&cmXpEHKtR>K<LLN7KF0Z)UVt~Xm&C=WUOX>nO#MA#ublsgiY@Uw
> >> zpZUFtt>)0<v(2GB%HJQJXM8n>A>x1Z#zqwz@d0um-qy(RO-6En_y=37v^gkC>yMH6
> >> z<NG9uD|3K5IMjI8;9T<YF$dHF@j;;uR%o^1>_;=l_f8tQ<7ooB>MCjDO#ZHEfmgA9
> >> z+E@bh(=Jxz8r%fTZoiGbsE;2<`6#=64);yc9-QAv{A@BxVDHvPEfN(T3UMC^h%a%m
> >> z?f}UJqg7lPi^WH5iI4TA{zA;{D{i$wOdW}h5%J9i!<K`vr_7cE#P6-W#>#=XfBqKV
> >> z-?2Ydw)zXP<=HE?_1MMy5nn(pkbjv2^1pZCm6R}CYQ#J&Z;o9oeqxD_pL_7LE@s}{
> >> z<@|4KTr}sFaSCil`5wPz>c!TW#Pz*9MDK4l=pSo*6gBvHokoVA$Lpk$d@sW1yxt=R
> >> z=+onUXC2#me9S?`oLO#*k2&-#9(=}tn3#jmvNo)qhxEL*L5(N)yQ@$5dmDgl#FQSx
> >> zsGm!)jrj1sW70T9lw&v5`V`26#5MWe4!|2AKIVe>5?ei&ah%@~U(n;XweF_XtNvt*
> >> zjd>uxfO$w<%mYYVse$-g&x9QDk$-^v1H{zt2VY)xFM%LG`vGC@9i9Era=ym%@tY^f
> >> z$Ffd$H$QLI&Y8I!f1kvxjm7D;wl3;Bo>MG(BBt(3{CxkRBk?oaqXcmM+_`F!MV!Ce
> >> z-7#;RijTSIv9axpkC;XvsN!P|5?9uR68p)@I5qF+QttX3<oaD0`QKl0e940z|Kn7P
> >> z%^h<=Y#oV<5pzLYkmEH65O0}-xa;vH_ZSiX-Nu#N>wG3-kbA@p1cM4aHnt@$Vgoo!
> >> zY>ayC^zDN?U*Y50O)t&)xw@WVjCehC=4iKm`YO6V_HB(VQ0%Muh1wt2BYZ}-K5*9l
> >> znSE^}$bN_|@%7KZ{`wr^Vg4>jL-xbxU>kErTzm$={-^fTT60)Djjz>Sw?&%I|2kFc
> >> zt4YW9Zy)&kHQ9gTJcEF~FSa{6dCkq=O9?x6@O$15<C@B9O4Wtbe%KeE<=kKP!{=Zg
> >> z*iU*`_Qz)khc?b2A+w*)y&N0+Nnc=J>?iZk@4ZtmRM6`$*HSDJpu=wu))_woiLh6J
> >> zzr*hUyyWLH;^){`ke_43=iuk~4Edbw2PxYB{9}Ay#OD~^#t4qQUZY6HLzM1_(|-Y0
> >> C>eV{{
> >>
> >> literal 0
> >> HcmV?d00001
> >>
> >> diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt
> >> index a5f080156..f6a2b69a9 100644
> >> --- a/tests/util/CMakeLists.txt
> >> +++ b/tests/util/CMakeLists.txt
> >> @@ -48,6 +48,7 @@ set(UTIL_GL_INCLUDES
> >>   set(UTIL_GL_SOURCES
> >>          fdo-bitmap.c
> >>          minmax-test.c
> >> +       piglit-dds.c
> >>          piglit-dispatch.c
> >>          piglit-dispatch-init.c
> >>          piglit-fbo.cpp
> >> diff --git a/tests/util/piglit-dds.c b/tests/util/piglit-dds.c
> >> new file mode 100644
> >> index 000000000..2ab6e6af5
> >> --- /dev/null
> >> +++ b/tests/util/piglit-dds.c
> >> @@ -0,0 +1,211 @@
> >> +#include <assert.h>
> >> +#include <stdarg.h>
> >> +#include <stdlib.h>
> >> +#include <string.h>
> >> +
> >> +#include "piglit-dds.h"
> >> +#include "piglit-util-gl.h"
> >> +
> >> +
> >> +// DDS values taken from http://www.mindcontrol.org/~hplus/graphics/dds-info/
> >> +
> >> +//  little-endian, of course
> >> +
> >> +//  DDS_header.dwFlags
> >> +#define DDSD_CAPS                   0x00000001
> >> +#define DDSD_HEIGHT                 0x00000002
> >> +#define DDSD_WIDTH                  0x00000004
> >> +#define DDSD_PITCH                  0x00000008
> >> +#define DDSD_PIXELFORMAT            0x00001000
> >> +#define DDSD_MIPMAPCOUNT            0x00020000
> >> +#define DDSD_LINEARSIZE             0x00080000
> >> +#define DDSD_DEPTH                  0x00800000
> >> +
> >> +//  DDS_header.sPixelFormat.dwFlags
> >> +#define DDPF_ALPHAPIXELS            0x00000001
> >> +#define DDPF_FOURCC                 0x00000004
> >> +#define DDPF_INDEXED                0x00000020
> >> +#define DDPF_RGB                    0x00000040
> >> +
> >> +//  DDS_header.sCaps.dwCaps1
> >> +#define DDSCAPS_COMPLEX             0x00000008
> >> +#define DDSCAPS_TEXTURE             0x00001000
> >> +#define DDSCAPS_MIPMAP              0x00400000
> >> +
> >> +//  DDS_header.sCaps.dwCaps2
> >> +#define DDSCAPS2_CUBEMAP            0x00000200
> >> +#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
> >> +#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
> >> +#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
> >> +#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
> >> +#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
> >> +#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
> >> +#define DDSCAPS2_VOLUME             0x00200000
> >> +
> >> +union DDS_header {
> >> +       struct {
> >> +               unsigned int    dwMagic;
> >> +               unsigned int    dwSize;
> >> +               unsigned int    dwFlags;
> >> +               unsigned int    dwHeight;
> >> +               unsigned int    dwWidth;
> >> +               unsigned int    dwPitchOrLinearSize;
> >> +               unsigned int    dwDepth;
> >> +               unsigned int    dwMipMapCount;
> >> +               unsigned int    dwReserved1[ 11 ];
> >> +
> >> +               //  DDPIXELFORMAT
> >> +               struct {
> >> +                       unsigned int    dwSize;
> >> +                       unsigned int    dwFlags;
> >> +                       unsigned int    dwFourCC;
> >> +                       unsigned int    dwRGBBitCount;
> >> +                       unsigned int    dwRBitMask;
> >> +                       unsigned int    dwGBitMask;
> >> +                       unsigned int    dwBBitMask;
> >> +                       unsigned int    dwAlphaBitMask;
> >> +               }               sPixelFormat;
> >> +
> >> +               //  DDCAPS2
> >> +               struct {
> >> +                       unsigned int    dwCaps1;
> >> +                       unsigned int    dwCaps2;
> >> +                       unsigned int    dwDDSX;
> >> +                       unsigned int    dwReserved;
> >> +               }               sCaps;
> >> +               unsigned int    dwReserved2;
> >> +       };
> >> +       char data[ 128 ];
> >> +};
> >> +
> >> +#define FOURCC(a, b, c, d)  ((a) << 0 | (b) << 8 | (c) << 16 | (d) << 24)
> >> +
> >> +#define DDS_MAGIC   FOURCC('D', 'D', 'S', ' ')
> >> +#define ATC_RGB     FOURCC('A', 'T', 'C', ' ')
> >> +#define ATC_RGBA_E  FOURCC('A', 'T', 'C', 'A')
> >> +#define ATC_RGBA_I  FOURCC('A', 'T', 'C', 'I')
> >> +
> >> +struct piglit_dds {
> >> +       struct piglit_dds_info info;
> >> +       uint8_t *data;
> >> +       size_t size;
> >> +
> >> +       struct piglit_dds_image *images;
> >> +};
> >> +
> >> +void
> >> +piglit_dds_destroy(struct piglit_dds *self)
> >> +{
> >> +       free(self->images);
> >> +       free(self->data);
> >> +       free(self);
> >> +}
> >> +
> >> +struct piglit_dds *
> >> +piglit_dds_read_file(const char *filename)
> >> +{
> >> +       struct piglit_dds *ret = calloc(1, sizeof(struct piglit_dds));
> >> +       FILE *f;
> >> +       bool success = false;
> >> +       int read, i, shift = 0, factor = 0;
> >> +       union DDS_header *header;
> >> +
> >> +       if (!ret)
> >> +               goto err_ret;
> >> +
> >> +       f = fopen(filename, "rb");
> >> +
> >> +       if (!f)
> >> +               goto err_file;
> >> +
> >> +       if (fseek(f, 0, SEEK_END))
> >> +               goto err_read;
> >> +       ret->size = ftell(f);
> >> +       if (fseek(f, 0, SEEK_SET))
> >> +               goto err_read;
> >> +
> >> +       ret->data = malloc(ret->size);
> >> +       if (!ret->data)
> >> +               goto err_read;
> >> +
> >> +       read = fread(ret->data, 1, ret->size, f);
> >> +       if (read < ret->size)
> >> +               goto err_read;
> >> +
> >> +       header = (union DDS_header*) ret->data;
> >> +
> >> +       if (header->dwMagic != DDS_MAGIC)
> >> +               goto err_read;
> >> +
> >> +       ret->info.num_miplevels = header->dwMipMapCount;
> >> +       ret->info.pixel_width = header->dwWidth;
> >> +       ret->info.pixel_height = header->dwHeight;
> >> +       switch (header->sPixelFormat.dwFourCC) {
> >> +       case 0:
> >> +               ret->info.gl_internal_format = GL_RGBA;
> >> +               factor = 4;
> >> +               break;
> >> +       case ATC_RGB:
> >> +               ret->info.gl_internal_format = GL_ATC_RGB_AMD;
> >> +               shift = 1;
> >> +               break;
> >> +       case ATC_RGBA_I:
> >> +               ret->info.gl_internal_format = GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
> >> +               break;
> >> +       case ATC_RGBA_E:
> >> +               ret->info.gl_internal_format = GL_ATC_RGBA_EXPLICIT_ALPHA_AMD;
> >> +               break;
> >> +       default:
> >> +               goto err_read;
> >> +       }
> >> +
> >> +       ret->images = calloc(ret->info.num_miplevels, sizeof(struct piglit_dds_image));
> >> +       for (i = 0; i < ret->info.num_miplevels; i++) {
> >> +               struct piglit_dds_image *img = &ret->images[i];
> >> +               if (i == 0) {
> >> +                       img->data = ret->data + 128;
> >> +                       img->pixel_width = ret->info.pixel_width;
> >> +                       img->pixel_height = ret->info.pixel_height;
> >> +               } else {
> >> +                       struct piglit_dds_image *prev = &ret->images[i - 1];
> >> +                       img->data = prev->data + prev->size;
> >> +                       img->pixel_width = MAX2(1, prev->pixel_width >> 1);
> >> +                       img->pixel_height = MAX2(1, prev->pixel_height >> 1);
> >> +               }
> >> +               if (header->sPixelFormat.dwFourCC)
> >> +                       img->size = ALIGN(img->pixel_width, 4) * ALIGN(img->pixel_height, 4);
> >> +               else
> >> +                       img->size = img->pixel_width * img->pixel_height;
> >> +               if (shift > 0)
> >> +                       img->size >>= shift;
> >> +               if (factor > 0)
> >> +                       img->size *= factor;
> >> +       }
> >> +
> >> +       success = true;
> >> +
> >> +err_read:
> >> +       fclose(f);
> >> +       if (success)
> >> +               return ret;
> >> +       if (ret->data)
> >> +               free(ret->data);
> >> +err_file:
> >> +       free(ret);
> >> +err_ret:
> >> +       return NULL;
> >> +}
> >> +
> >> +const struct piglit_dds_info *
> >> +piglit_dds_get_info(struct piglit_dds *self)
> >> +{
> >> +       return &self->info;
> >> +}
> >> +
> >> +const struct piglit_dds_image *
> >> +piglit_dds_get_image(struct piglit_dds *self,
> >> +                     int miplevel)
> >> +{
> >> +       assert(miplevel < self->info.num_miplevels);
> >> +       return &self->images[miplevel];
> >> +}
> >> diff --git a/tests/util/piglit-dds.h b/tests/util/piglit-dds.h
> >> new file mode 100644
> >> index 000000000..28660b99d
> >> --- /dev/null
> >> +++ b/tests/util/piglit-dds.h
> >> @@ -0,0 +1,72 @@
> >> +/*
> >> + * Copyright 2015 Ilia Mirkin
> >> + *
> >> + * 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
> >> + *
> >> + * \brief Utilities for the DDS file format
> >> + *
> >> + * The DDS file format specifies a simple format for storing texture
> >> + * miptrees.
> >> + */
> >> +
> >> +#include <stdint.h>
> >> +
> >> +#ifdef __cplusplus
> >> +extern "C" {
> >> +#endif
> >> +
> >> +struct piglit_dds;
> >> +
> >> +struct piglit_dds_info {
> >> +  uint32_t gl_internal_format;
> >> +  uint32_t num_miplevels;
> >> +
> >> +  uint32_t pixel_width;
> >> +  uint32_t pixel_height;
> >> +};
> >> +
> >> +struct piglit_dds_image {
> >> +  const uint8_t *data;
> >> +  size_t size;
> >> +
> >> +  uint32_t pixel_width;
> >> +  uint32_t pixel_height;
> >> +};
> >> +
> >> +void
> >> +piglit_dds_destroy(struct piglit_dds *self);
> >> +
> >> +struct piglit_dds *
> >> +piglit_dds_read_file(const char *filename);
> >> +
> >> +const struct piglit_dds_info *
> >> +piglit_dds_get_info(struct piglit_dds *self);
> >> +
> >> +const struct piglit_dds_image *
> >> +piglit_dds_get_image(struct piglit_dds *self,
> >> +                     int miplevel);
> >> +
> >> +#ifdef __cplusplus
> >> +}
> >> +#endif
> >> --
> >> 2.17.1
> >>