[Piglit] [RFC 3/3] tests/spec: add tests for oes image external

Topi Pohjolainen topi.pohjolainen at intel.com
Tue Feb 26 05:15:48 PST 2013


This consists of tests adapted from Khronos conformance suite and
Android surface flinger. While the former deals with "getters/setters",
enumrations and simple sampling of texture based images, the latter
addresses bilinear sampling of non-GPU written subsampled UV-planes
and conversion from YUV to RGB.

The original Android test consist of two YV12 formatted textures,
one of size 64x64 and another of size 64x66. Both represent checker
board pattern each YUV component having value 63 or 191. Here I have
only the first but I'm planning to adopt the latter also if the approach
I have taken is reasonable. Instead of filling in the entire pattern I
have only written those YUV-components that are actually checked (a
dozen odd pixels) while the rest are initialised to zero. In addition
I used calculated floating point values instead of the hardcoded found
in the original. There, however, I ended up in deviations and I would
appreciate if people understanding the domain of YUV to RGB conversion
better could take a good look.

In the implementation that I have written for mesa/i965 I have also
support for NV12 format. Whereas YV12 (YVU420) has separate U- and
V-planes, NV12 has them combined into one. Hence I would like to have
the same tests for NV12 as for YV12 if acceptable.

The tests are written only for ES2 contexts, I haven't looked into
how I would separate the tests not dealing with external sampler
(samplerExternalOES is only defined for ES 2.x).

Signed-off-by: Topi Pohjolainen <topi.pohjolainen at intel.com>
---
 tests/spec/CMakeLists.txt                          |    1 +
 .../oes_egl_image_external/CMakeLists.gles2.txt    |   16 +
 tests/spec/oes_egl_image_external/CMakeLists.txt   |    3 +
 .../oes_egl_image_external.c                       |  776 ++++++++++++++++++++
 4 files changed, 796 insertions(+)
 create mode 100644 tests/spec/oes_egl_image_external/CMakeLists.gles2.txt
 create mode 100644 tests/spec/oes_egl_image_external/CMakeLists.txt
 create mode 100644 tests/spec/oes_egl_image_external/oes_egl_image_external.c

diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
index 96b5a61..485cf5e 100644
--- a/tests/spec/CMakeLists.txt
+++ b/tests/spec/CMakeLists.txt
@@ -66,6 +66,7 @@ add_subdirectory (ext_texture_array)
 add_subdirectory (ext_texture_integer)
 add_subdirectory (arb_draw_buffers)
 add_subdirectory (oes_draw_texture)
+add_subdirectory (oes_egl_image_external)
 add_subdirectory (arb_blend_func_extended)
 add_subdirectory (ext_unpack_subimage)
 add_subdirectory (arb_vertex_array_object)
diff --git a/tests/spec/oes_egl_image_external/CMakeLists.gles2.txt b/tests/spec/oes_egl_image_external/CMakeLists.gles2.txt
new file mode 100644
index 0000000..1ae1792
--- /dev/null
+++ b/tests/spec/oes_egl_image_external/CMakeLists.gles2.txt
@@ -0,0 +1,16 @@
+#add_definitions(-DSOURCE_DIR="${piglit_SOURCE_DIR}/")
+
+include_directories(
+	${OPENGL_INCLUDE_PATH}
+	)
+
+link_libraries(
+	${OPENGL_egl_LIBRARY}
+	piglitutil_gles2
+	)
+
+piglit_add_executable(oes_egl_image_external_gles2
+	oes_egl_image_external.c
+	)
+
+# vim: ft=cmake:
diff --git a/tests/spec/oes_egl_image_external/CMakeLists.txt b/tests/spec/oes_egl_image_external/CMakeLists.txt
new file mode 100644
index 0000000..d9d41f2
--- /dev/null
+++ b/tests/spec/oes_egl_image_external/CMakeLists.txt
@@ -0,0 +1,3 @@
+if(OPENGL_egl_LIBRARY)
+	piglit_include_target_api()
+endif(OPENGL_egl_LIBRARY)
diff --git a/tests/spec/oes_egl_image_external/oes_egl_image_external.c b/tests/spec/oes_egl_image_external/oes_egl_image_external.c
new file mode 100644
index 0000000..b04c72c
--- /dev/null
+++ b/tests/spec/oes_egl_image_external/oes_egl_image_external.c
@@ -0,0 +1,776 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Author: Topi Pohjolainen <topi.pohjolainen at intel.com>
+ */
+
+/** @file oes_egl_image_external.c
+ *
+ * Test EGL_OES_image_external.
+ */
+
+#define EGL_EGLEXT_PROTOTYPES 1
+#define GL_GLEXT_PROTOTYPES 1
+#include "piglit-util-gl-common.h"
+#include "piglit-util-egl.h"
+
+#include <EGL/eglext.h>
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_es_version = 20;
+
+	config.window_visual = PIGLIT_GL_VISUAL_RGBA;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/**
+ * Limited range:
+ *    y   [16, 235] -> 219 steps
+ *    u,v [16, 240] -> 224 steps
+ *
+ * 1.164 = 255.0 / 219
+ * 1.596 = 1.402 * 255.0 / 224
+ * 0.813 = 0.714 * 255.0 / 224
+ * 0.391 = 0.344 * 255.0 / 224
+ * 2.018 = 1.772 * 255.0 / 224
+ */
+#define YUV_TO_R_BT601_LIMITED_RANGE(y, v) \
+	(1.164f * ((y) - 16) + 1.596f * ((v) - 128))
+#define YUV_TO_G_BT601_LIMITED_RANGE(y, u, v) \
+	(1.164f * ((y) - 16) - 0.813f * ((v) - 128) - 0.391f * ((u) - 128))
+#define YUV_TO_B_BT601_LIMITED_RANGE(y, u) \
+	(1.164f * ((y) - 16) + 2.018f * ((u) - 128))
+#define CLIP_0_1(v) ((v) > 1.0 ? 1.0 : (v) < 0.0 ? 0.0 : (v))
+
+static int 
+check_pixel_(int x_pos, int y_pos, int y, int u, int v)
+{
+	float expected[] = {
+		CLIP_0_1(YUV_TO_R_BT601_LIMITED_RANGE(y,    v) / 255.0f),
+		CLIP_0_1(YUV_TO_G_BT601_LIMITED_RANGE(y, u, v) / 255.0f),
+		CLIP_0_1(YUV_TO_B_BT601_LIMITED_RANGE(y, u   ) / 255.0f),
+		1.0 };
+
+	return piglit_probe_pixel_rgba(x_pos, y_pos, expected);
+}
+
+static const char fs_src[] =
+	"#extension GL_OES_EGL_image_external : require\n"
+	"uniform samplerExternalOES sampler;\n"
+	"varying vec2 texcoords;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"gl_FragColor = texture2D(sampler, texcoords);\n"
+	"}\n";
+static const char vs_src[] =
+	"attribute vec4 position;\n"
+	"varying vec2 texcoords;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"texcoords = 0.5 * (position.xy + vec2(1.0, 1.0));\n"
+	"gl_Position = position;\n"
+	"}\n";
+
+static GLuint 
+make_program(const char *vs, const char *fs)
+{
+	GLuint prog, tmp;
+
+	prog = glCreateProgram();
+
+	tmp = piglit_compile_shader_text(GL_VERTEX_SHADER, vs);
+	glAttachShader(prog, tmp);
+
+	tmp = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs);
+	glAttachShader(prog, tmp);
+
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog))
+		piglit_report_result(PIGLIT_FAIL);
+
+	glUseProgram(prog);
+
+	return prog;
+}
+
+void set_vertices(GLuint prog)
+{
+	static const GLfloat v[] = { -1.0f,  1.0f, -1.0f, -1.0f,
+				      1.0f, -1.0f,  1.0f,  1.0f };
+
+	GLint i = glGetAttribLocation(prog, "position");
+	glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, 0, v);
+	glEnableVertexAttribArray(i);
+}
+
+static void
+write_64x64_420(unsigned char *y, unsigned char *u, unsigned char *v)
+{
+	(void)memset(y, 0, 64 * 64);
+	(void)memset(u, 0, 32 * 32);
+	(void)memset(v, 0, 32 * 32);
+
+	/* 0,0 */
+	y[0] = 63;
+	u[0] = 63;
+	v[0] = 63;
+
+	/* 63,0 */
+	y[63] = 191;
+	u[31] = 191;
+	v[31] = 191;
+
+	/* 63,63 */
+	y[63 * 64 + 63] = 63;
+	u[31 * 32 + 31] = 63;
+	v[31 * 32 + 31] = 63;
+
+	/* 0,63 */
+	y[63 * 64 + 0] = 191;
+	u[31 * 32 + 0] = 191;
+	v[31 * 32 + 0] = 191;
+
+	/* 22,19 */
+	y[19 * 64 + 22] = 191;
+	u[ 9 * 32 + 10] = 63;
+	u[ 9 * 32 + 11] = 63;
+	u[10 * 32 + 10] = 63;
+	u[10 * 32 + 11] = 63;
+	v[ 9 * 32 + 10] = 63;
+	v[ 9 * 32 + 11] = 63;
+	v[10 * 32 + 10] = 63;
+	v[10 * 32 + 11] = 63;
+
+	/* 45,11 */
+	y[11 * 64 + 45] = 191;
+	u[ 5 * 32 + 22] = 63;
+	u[ 5 * 32 + 23] = 63;
+	u[ 6 * 32 + 22] = 63;
+	u[ 6 * 32 + 23] = 63;
+	v[ 5 * 32 + 22] = 63;
+	v[ 5 * 32 + 23] = 63;
+	v[ 6 * 32 + 22] = 63;
+	v[ 6 * 32 + 23] = 63;
+
+	/* 52,12 */
+	y[12 * 64 + 52] = 63;
+	u[ 5 * 32 + 25] = 191;
+	u[ 5 * 32 + 26] = 191;
+	u[ 6 * 32 + 25] = 191;
+	u[ 6 * 32 + 26] = 191;
+	v[ 5 * 32 + 25] = 191;
+	v[ 5 * 32 + 26] = 191;
+	v[ 6 * 32 + 25] = 191;
+	v[ 6 * 32 + 26] = 191;
+
+	/* 7,32 */
+	y[32 * 64 + 7] = 191;
+	u[15 * 32 + 3] = 191;
+	u[15 * 32 + 4] =  63;
+	u[16 * 32 + 3] =  63;
+	u[16 * 32 + 4] = 191;
+	v[15 * 32 + 3] = 191;
+	v[15 * 32 + 4] = 191;
+	v[16 * 32 + 3] =  63;
+	v[16 * 32 + 4] =  63;
+
+	/* 31,54 */
+	y[54 * 64 + 31] =  63;
+	u[26 * 32 + 15] = 191;
+	u[26 * 32 + 16] =  63;
+	u[27 * 32 + 15] = 191;
+	u[27 * 32 + 16] =  63;
+	v[26 * 32 + 15] =  63;
+	v[26 * 32 + 16] = 191;
+	v[27 * 32 + 15] =  63;
+	v[27 * 32 + 16] = 191;
+
+	/* 29,28 */
+	y[28 * 64 + 29] = 63;
+	u[13 * 32 + 14] = 63;
+	u[13 * 32 + 15] = 63;
+	u[14 * 32 + 14] = 63;
+	u[14 * 32 + 15] = 63;
+	v[13 * 32 + 14] = 63;
+	v[13 * 32 + 15] = 63;
+	v[14 * 32 + 14] = 63;
+	v[14 * 32 + 15] = 63;
+
+	/* 36,41 */
+	y[41 * 64 + 36] = 191;
+	u[20 * 32 + 17] = 191;
+	u[20 * 32 + 18] = 191;
+	u[21 * 32 + 17] = 191;
+	u[21 * 32 + 18] = 191;
+	v[20 * 32 + 17] =  63;
+	v[20 * 32 + 18] =  63;
+	v[21 * 32 + 17] =  63;
+	v[21 * 32 + 18] =  63;
+}
+
+static void 
+sample_and_destroy(unsigned w, unsigned h, EGLImageKHR img)
+{
+	GLuint prog, tex;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+
+	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES,
+				(GLeglImageOES)img);
+
+	prog = make_program(vs_src, fs_src);
+
+	glUniform1i(glGetUniformLocation(prog, "sampler"), 0);
+	set_vertices(prog);
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	glViewport(0, 0, w, h);
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+	glDeleteProgram(prog);
+	glUseProgram(0);
+
+	eglDestroyImageKHR(eglGetCurrentDisplay(), img);
+	glDeleteTextures(1, &tex);
+}
+
+/**
+ * This is a test adapted from Android surface flinger. Whereas in the original
+ * test each of the YUV-planes are filled with a checker board pattern, here one
+ * sets only those pixels that contribute to sampling leaving the rest
+ * initialised to zero. The size 64x64 is chosen to stimulate bilinear sampling
+ * of the sub-sampled UV-planes with weights of 0.25 and 0.75 instead of just
+ * equally with weights of 0.5.
+ * The orientation of the texture is also flipped vertically, original test uses
+ * transformation matrix moving 0,0 to the lower left corner, here one samples
+ * directly keeping 0,0 in the upper left corner of the texture.
+ *
+ * Deviations to values expected by surface flinger test:
+ *     (63, 0) green: 127 vs. 0.501365 * 255 = 127.848
+ *     (0 ,63) green: 127 vs. 0.501365 * 255 = 127.848
+ *     (22,19)  blue:  74 vs. 0.284431 * 255 =  72.530
+ *     (45,11)  blue:  74 vs. 0.284431 * 255 =  72.530
+ *     (52,12)  blue: 181 vs. 0.713106 * 255 = 181.842
+ *     ( 7,32)   red: 150 vs. 0.592282 * 255 = 151.032
+ *     ( 7,32)  blue: 170 vs. 0.664290 * 255 = 169.394
+ *     (31,54)   red:   0 vs. 0.008000 * 255 =   2.040
+ *     (31,54) green:  71 vs. 0.272219 * 255 =  69.416
+ */
+static bool
+test_64x64_yv12(void)
+{
+	bool pass;
+	unsigned char y[64 * 64];
+	unsigned char u[32 * 32];
+	unsigned char v[32 * 32];
+	EGLImageKHR img;
+	void *buf;
+
+	write_64x64_420(y, u, v);
+	/* Reversing the order of UV-planes gives YVU420 a.k.a. YV12 */
+	buf = piglit_create_ext_420_buf(64, 64, true, y, u, v);
+	if (!buf) {
+		printf("failed to create external buffer\n");
+		return false;
+	}
+
+	img = eglCreateImageKHR(eglGetCurrentDisplay(), 0,
+			EGL_NATIVE_PIXMAP_KHR, buf, 0);
+	if (img == EGL_NO_IMAGE_KHR) {
+		piglit_destroy_ext_buf(buf);
+		return false;
+	}
+
+	sample_and_destroy(64, 64, img);
+	piglit_destroy_ext_buf(buf);
+
+        pass = check_pixel_( 0,  0,  63,  63,  63);
+        pass = check_pixel_(63,  0, 191, 191, 191) && pass;
+        pass = check_pixel_(63, 63,  63,  63,  63) && pass;
+        pass = check_pixel_( 0, 63, 191, 191, 191) && pass;
+        pass = check_pixel_(22, 19, 191,  63,  63) && pass;
+        pass = check_pixel_(45, 11, 191,  63,  63) && pass;
+        pass = check_pixel_(52, 12,  63, 191, 191) && pass;
+
+        pass = check_pixel_(7, 32,
+			191,
+			0.25 * (0.75 * 191 + 0.25 * 63) +
+			0.75 * (0.25 * 191 + 0.75 * 63),
+			0.25 * 191 + 0.75 * 63) && pass;
+
+        pass = check_pixel_(31, 54,
+			63,
+			0.75 * 191 + 0.25 * 63,
+			0.25 * 191 + 0.75 * 63) && pass;
+
+        pass = check_pixel_(29, 28,  63,  63, 63) && pass;
+        pass = check_pixel_(36, 41, 191, 191, 63) && pass;
+
+	return pass;
+}
+
+static bool
+test_get_binding(void)
+{
+	GLint i;
+	GLfloat f;
+
+	glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &i);
+	if (i != 0) {
+		printf("default binding EXTERNAL_OES must be zero\n");
+		return false;
+	}		
+
+	glGetFloatv(GL_TEXTURE_BINDING_EXTERNAL_OES, &f);
+	if (f != 0) {
+		printf("default binding EXTERNAL_OES must be zero\n");
+		return false;
+	}		
+
+	return true;
+}
+
+static bool
+test_required_image_units(void)
+{
+	GLint i;
+	GLfloat f;
+
+	glGetTexParameteriv(GL_TEXTURE_EXTERNAL_OES,
+		GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES, &i);
+
+	if (i < 1 || i > 3) {
+		printf("REQUIRED_TEXTURE_IMAGE_UNITS_OES "
+			"should be between 1-3\n");
+		return false;
+	}
+
+	glGetTexParameterfv(GL_TEXTURE_EXTERNAL_OES,
+		GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES, &f);
+
+	if ((GLfloat)i != f) {
+		printf("mismatch between integer and float value of "
+			"REQUIRED_TEXTURE_IMAGE_UNITS_OES %d:%f\n", i, f);
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * INVALID_ENUM should be generated for TexImage2D, TexSubImage2D,
+ * CompressedTexImager2D and CompressedTexSubImage2D with
+ * TEXTURE_EXTERNAL_OES.
+ */
+static bool
+test_disallow_image_2d(void)
+{
+	GLushort pixel_2x2_565[] = { 0, 0, 0, 0 };
+	GLuint tex;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+
+	glTexImage2D(GL_TEXTURE_EXTERNAL_OES, 0, GL_RGB, 2, 2, 0, GL_RGB,
+		GL_UNSIGNED_SHORT_5_6_5, pixel_2x2_565);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("TexImage2D() cannot be invoked for EXTERNAL_OES\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+		
+	glTexSubImage2D(GL_TEXTURE_EXTERNAL_OES, 0, 0, 0, 2, 2, GL_RGB,
+			GL_UNSIGNED_SHORT_5_6_5, pixel_2x2_565);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("TexSubImage2D() cannot be invoked for EXTERNAL_OES\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glDeleteTextures(1, &tex);
+	return true;
+}
+
+static bool
+test_default_filter_mode(void)
+{
+	GLuint tex;
+	GLint param;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+
+	glGetTexParameteriv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER,
+			&param);
+	if (param != GL_LINEAR) {
+		printf("default TEXTURE_MAG_FILTER must be LINEAR\n");
+		glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glGetTexParameteriv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
+			&param);
+	if (param != GL_LINEAR) {
+		printf("default TEXTURE_MIN_FILTER must be LINEAR\n");
+		glDeleteTextures(1, &tex);
+		return false;
+	}
+
+    	glGetTexParameteriv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, &param);
+	if (param != GL_CLAMP_TO_EDGE) {
+		printf("default TEXTURE_WRAP_S must be CLAMP_TO_EDGE\n");
+		glDeleteTextures(1, &tex);
+		return false;
+	}
+
+    	glGetTexParameteriv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, &param);
+	if (param != GL_CLAMP_TO_EDGE) {
+		printf("default TEXTURE_WRAP_T must be CLAMP_TO_EDGE\n");
+		glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glDeleteTextures(1, &tex);
+	return true;
+}
+
+static bool
+test_invalid_filter_mode(void)
+{
+	GLuint tex;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
+		GL_NEAREST_MIPMAP_NEAREST);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("MIN_FILTER cannot be set to NEAREST_MIPMAP_NEAREST\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+		
+    	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
+		GL_NEAREST_MIPMAP_LINEAR);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("MIN_FILTER cannot be set to NEAREST_MIPMAP_LINEAR\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+    	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
+		GL_LINEAR_MIPMAP_NEAREST);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("MIN_FILTER cannot be set to LINEAR_MIPMAP_NEAREST\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+    	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
+		GL_LINEAR_MIPMAP_LINEAR);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("MIN_FILTER cannot be set to LINEAR_MIPMAP_LINEAR\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("TEXTURE_WRAP_S cannot be set to REPEAT\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S,
+		GL_MIRRORED_REPEAT);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("TEXTURE_WRAP_S cannot be set to MIRRORED_REPEAT\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_REPEAT);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("TEXTURE_WRAP_T cannot be set to REPEAT\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T,
+		GL_MIRRORED_REPEAT);
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("TEXTURE_WRAP_T cannot be set to MIRRORED_REPEAT\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
+	glDeleteTextures(1, &tex);
+	return true;
+}
+
+static bool
+test_disallow_mipmap_generation(void)
+{
+	GLuint tex;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+	glGenerateMipmap(GL_TEXTURE_EXTERNAL_OES);
+
+	if (glGetError() != GL_INVALID_ENUM) {
+		printf("GenerateMipmap cannot be called for EXTERNAL_OES\n");
+        	glDeleteTextures(1, &tex);
+		return false;
+	}
+
+	glDeleteTextures(1, &tex);
+    	return true;
+}
+
+static bool
+test_missing_require_directive(void)
+{
+	const GLchar *src[] = { "uniform samplerExternalOES sampler;\n"
+			        "varying vec2 p;\n"
+			        "void main()\n"
+			        "{ gl_FragColor = texture2D(sampler, p); }\n" };
+	GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+	GLint status;
+
+	glShaderSource(fs, 1, src, 0);
+	glCompileShader(fs);
+	glGetShaderiv(fs, GL_COMPILE_STATUS, &status);
+
+	if (status != 0)
+		printf("samplerExternalOES cannot be used without requiring "
+			"OES_EGL_image_external\n");
+
+	glDeleteShader(fs);
+
+	return status == 0;
+}
+
+static bool
+test_get_active_uniform(void)
+{
+    	GLint active_n;
+	bool result = false;
+	GLuint prog = make_program(vs_src, fs_src);
+
+	glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &active_n);
+
+	if (active_n == 1) {
+    		char name[32];
+		GLint size;
+		GLenum type;
+
+		glGetActiveUniform(prog, 0, sizeof(name), 0, &size, &type,
+				name);
+
+		if (strncmp(name, "sampler", sizeof(name)) == 0 && size == 1 &&
+			type == GL_SAMPLER_EXTERNAL_OES)
+				result = true;
+        }
+
+	glDeleteProgram(prog);
+
+	return result;
+}
+
+static bool
+test_create_external_texture(void)
+{
+	EGLImageKHR img;
+	GLuint tex;
+	unsigned char y[2 * 2];
+	unsigned char u[1 * 1];
+	unsigned char v[1 * 1];
+	void *buf = piglit_create_ext_420_buf(2, 2, true, y, u, v);
+	EGLDisplay dpy = eglGetCurrentDisplay();
+	bool result = true;
+
+	if (!buf) {
+		printf("failed to create external buffer\n");
+		return false;
+	}
+
+	img = eglCreateImageKHR(dpy, 0, EGL_NATIVE_PIXMAP_KHR, buf, 0);
+	if (img == EGL_NO_IMAGE_KHR) {
+		piglit_destroy_ext_buf(buf);
+		return false;
+	}
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+
+	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES,
+				(GLeglImageOES)img);
+
+	if (glGetError() != GL_NO_ERROR) {
+		printf("failed to create external texture\n");
+		result = false;
+	}
+
+        glDeleteTextures(1, &tex);
+	eglDestroyImageKHR(dpy, img);
+	piglit_destroy_ext_buf(buf);
+
+	return result;
+}
+
+static bool
+test_detect_invalid_image(void)
+{
+	GLuint tex;
+	bool result = true;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+
+	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)0);
+
+	if (glGetError() != GL_INVALID_OPERATION) {
+		printf("external texture cannot be targeted with null image\n");
+		result = false;
+	}
+
+        glDeleteTextures(1, &tex);
+
+	return result;
+}
+
+/**
+ * Sampling an external texture which is not associated with any EGLImage
+ * sibling will return a sample value of (0,0,0,1).
+ */
+static bool
+test_no_associated_image(void)
+{
+	const float expected[] = { 0, 0, 0, 1.0 };
+	GLuint prog, tex;
+	bool result;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
+
+	prog = make_program(vs_src, fs_src);
+
+	glUniform1i(glGetUniformLocation(prog, "sampler"), 0);
+	set_vertices(prog);
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	glViewport(0, 0, 1, 1);
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+	result = piglit_probe_pixel_rgba(0, 0, expected);
+
+	glDeleteProgram(prog);
+	glUseProgram(0);
+	glDeleteTextures(1, &tex);
+
+	return result;
+}
+
+static EGLImageKHR
+create_tex_based_egl_image(unsigned w, unsigned h, const unsigned char *pixels)
+{
+	GLuint tex;
+	EGLImageKHR img;
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_2D, tex);
+
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+		GL_UNSIGNED_BYTE, pixels);
+
+	img = eglCreateImageKHR(eglGetCurrentDisplay(), eglGetCurrentContext(),
+			EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)tex, 0);
+	if (!img)
+		printf("failed to create EGL image out of texture\n");
+
+	glDeleteTextures(1, &tex);
+
+	return img;
+}
+
+static bool
+test_simple_external_from_tex_based_egl_image(void)
+{
+	const unsigned char src[] = {
+		0x00, 0xff, 0x00, 0xff,	0x12, 0x34, 0x56, 0x78,	
+		0x90, 0xab, 0xcd, 0xef,	0x1a, 0x2b, 0x3c, 0x4e };
+	const float expected[] = { src[0] / 255.0, src[1] / 255.0,
+		src[2] / 255.0, src[3] / 255.0, src[4] / 255.0, src[5] / 255.0,
+		src[6] / 255.0, src[7] / 255.0, src[8] / 255.0, src[9] / 255.0,
+		src[10] / 255.0, src[11] / 255.0, src[12] / 255.0,
+		src[13] / 255.0, src[14] / 255.0, src[15] / 255.0 };
+	EGLImageKHR img = create_tex_based_egl_image(2, 2, src);
+	bool res;
+
+	if (!img)
+		return false;
+
+	sample_and_destroy(2, 2, img);
+
+	res = piglit_probe_pixel_rgba(0, 0, expected +  0);
+	res = piglit_probe_pixel_rgba(1, 0, expected +  4) && res;
+	res = piglit_probe_pixel_rgba(0, 1, expected +  8) && res;
+	res = piglit_probe_pixel_rgba(1, 1, expected + 12) && res;
+
+	return res;
+}
+
+enum piglit_result
+piglit_display(void)
+{
+	bool pass = test_get_binding();
+
+	pass = test_required_image_units() && pass;
+	pass = test_disallow_image_2d() && pass;
+	pass = test_default_filter_mode() && pass;
+	pass = test_invalid_filter_mode() && pass;
+	pass = test_disallow_mipmap_generation() && pass; 
+	pass = test_missing_require_directive() && pass;
+	pass = test_get_active_uniform() && pass;
+	pass = test_create_external_texture() && pass;
+	pass = test_detect_invalid_image() && pass;
+	pass = test_no_associated_image() && pass;
+	pass = test_simple_external_from_tex_based_egl_image() && pass;
+	pass = test_64x64_yv12() && pass;
+
+	piglit_present_results();
+
+	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	piglit_require_extension("GL_OES_EGL_image_external");
+}
-- 
1.7.9.5



More information about the Piglit mailing list