egl: Add tests for EGL_EXT_device_base v2.

Submitted by Mathias Fröhlich on April 10, 2019, 9:10 a.m.

Details

Message ID 05a00c184742a1602b3df770ccc55e38b7187752.1554887058.git.Mathias.Froehlich@gmx.net
State New
Headers show
Series "egl: Add tests for EGL_EXT_device_base v2." ( rev: 1 ) in Piglit

Not browsing as part of any series.

Commit Message

Mathias Fröhlich April 10, 2019, 9:10 a.m.
From: Mathias Fröhlich <mathias.froehlich@web.de>

Hi all,

Below is a new test that should test the about to be arriving egl device
extension. The test goes a bit further than just creating a context and
destroying it as it clears and paints into the buffer and checks the result.

This actually uncovers problems with the current egl implementation that
also show up with the new device extension.

Please review
best

Mathias



The new test walks all available devices and makes sure that
context creation works as well as painting a rectangle.

Signed-off-by: Mathias Froehlich <Mathias.Froehlich@web.de>
---
 tests/egl/spec/CMakeLists.txt                 |   1 +
 .../egl_ext_device_base/CMakeLists.gl.txt     |   4 +
 .../spec/egl_ext_device_base/CMakeLists.txt   |   1 +
 .../egl_ext_device_base/egl_ext_device_base.c | 460 ++++++++++++++++++
 tests/opengl.py                               |   6 +
 5 files changed, 472 insertions(+)
 create mode 100644 tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt
 create mode 100644 tests/egl/spec/egl_ext_device_base/CMakeLists.txt
 create mode 100644 tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c

--
2.20.1

Patch hide | download patch | download mbox

diff --git a/tests/egl/spec/CMakeLists.txt b/tests/egl/spec/CMakeLists.txt
index 378c8d725..45a681b28 100644
--- a/tests/egl/spec/CMakeLists.txt
+++ b/tests/egl/spec/CMakeLists.txt
@@ -1,5 +1,6 @@ 
 add_subdirectory (egl-1.4)
 add_subdirectory (egl_ext_client_extensions)
+add_subdirectory (egl_ext_device_base)
 add_subdirectory (egl_ext_device_query)
 add_subdirectory (egl_ext_device_enumeration)
 add_subdirectory (egl_ext_device_drm)
diff --git a/tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt b/tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt
new file mode 100644
index 000000000..2b65d07da
--- /dev/null
+++ b/tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt
@@ -0,0 +1,4 @@ 
+
+piglit_add_executable(egl_ext_device_base egl_ext_device_base.c)
+
+# vim: ft=cmake:
diff --git a/tests/egl/spec/egl_ext_device_base/CMakeLists.txt b/tests/egl/spec/egl_ext_device_base/CMakeLists.txt
new file mode 100644
index 000000000..144a306f4
--- /dev/null
+++ b/tests/egl/spec/egl_ext_device_base/CMakeLists.txt
@@ -0,0 +1 @@ 
+piglit_include_target_api()
diff --git a/tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c b/tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c
new file mode 100644
index 000000000..445f4f61c
--- /dev/null
+++ b/tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c
@@ -0,0 +1,460 @@ 
+/*
+ * Copyright 2019 Mathias Fröhlich <Mathias.Froehlich@web.de>.
+ *
+ * Copyright 2018 Collabora, Ltd.
+ *
+ * Based on ext_mesa_platform_surfaceless.c which has
+ * Copyright 2016 Google
+ *
+ * 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.
+ */
+
+/*
+ * Test that enumerates all egl devices and tries to create an offscreen buffer
+ * for each device, does a bunch of gl calls on it and tears down the objects
+ * on the device again.
+ */
+
+#include <stdlib.h>
+
+#include "piglit-util.h"
+#include "piglit-util-egl.h"
+#include "piglit-util-gl.h"
+
+
+#define WIDTH 16
+
+
+/* Extension function pointers.
+ *
+ * Use prefix 'pegl' (piglit egl) instead of 'egl' to avoid collisions with
+ * prototypes in eglext.h.
+ */
+
+const char *(*peglQueryDeviceStringEXT)(EGLDeviceEXT device, EGLint name);
+EGLBoolean (*peglQueryDevicesEXT)(EGLint max_devices, EGLDeviceEXT *devices,
+	    EGLint *num_devices);
+EGLDisplay (*peglGetPlatformDisplayEXT)(EGLenum platform, void *native_display,
+	    const EGLint *attrib_list);
+
+static void
+init_egl_extension_funcs(void)
+{
+	peglQueryDeviceStringEXT = (void *)eglGetProcAddress("eglQueryDeviceStringEXT");
+	peglQueryDevicesEXT = (void *)eglGetProcAddress("eglQueryDevicesEXT");
+	peglGetPlatformDisplayEXT = (void *)eglGetProcAddress("eglGetPlatformDisplayEXT");
+}
+
+
+static enum piglit_result
+commands()
+{
+	const GLfloat blue[3] = { 0, 0, 1 };
+	const GLfloat red[3] = { 1, 0, 0 };
+
+	printf("GL Vendor: %s\n", glGetString(GL_VENDOR));
+	printf("GL Renderer: %s\n", glGetString(GL_RENDERER));
+	printf("GL Version: %s\n", glGetString(GL_VERSION));
+
+	glClearColor(blue[0], blue[1], blue[2], 1);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	if (!piglit_probe_pixel_rgb(WIDTH/2, WIDTH/2, blue)) {
+		printf("Pixel probe failed\n");
+		return PIGLIT_FAIL;
+	}
+
+	glColor3fv(red);
+	piglit_draw_rect(-1, -1, 2, 2);
+
+	if (!piglit_probe_pixel_rgb(WIDTH/2, WIDTH/2, red)) {
+		printf("Pixel probe failed\n");
+		return PIGLIT_FAIL;
+	}
+
+	if (!piglit_check_gl_error(0)) {
+		printf("Got OpenGL errors\n");
+		return PIGLIT_FAIL;
+	}
+
+	return PIGLIT_PASS;
+}
+
+
+static enum piglit_result
+commands_with_fbo()
+{
+	enum piglit_result result;
+	GLuint fb, cb, db;
+	GLenum status;
+
+	if (!piglit_is_extension_supported("GL_ARB_framebuffer_object")) {
+		printf("No GL_ARB_framebuffer_object available\n");
+		return PIGLIT_SKIP;
+	}
+
+	glGenRenderbuffers(1, &cb);
+	glBindRenderbuffer(GL_RENDERBUFFER, cb);
+	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, WIDTH, WIDTH);
+	glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+	glGenRenderbuffers(1, &db);
+	glBindRenderbuffer(GL_RENDERBUFFER, db);
+	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, WIDTH, WIDTH);
+	glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+	glGenFramebuffers(1, &fb);
+	glBindFramebuffer(GL_FRAMEBUFFER, fb);
+	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cb);
+	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, db);
+
+	status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+	if (status != GL_FRAMEBUFFER_COMPLETE) {
+		printf("FBO incomplete status 0x%X\n", status);
+		return PIGLIT_FAIL;
+	}
+
+	glViewport(0, 0, WIDTH, WIDTH);
+
+	result = commands();
+
+	glDeleteFramebuffers(1, &fb);
+	glDeleteRenderbuffers(1, &cb);
+	glDeleteRenderbuffers(1, &db);
+
+	return result;
+}
+
+
+static enum piglit_result
+pbuffer_test(EGLDisplay dpy)
+{
+	/* We are after desktop OpenGL - like requested in the config */
+	if (!eglBindAPI(EGL_OPENGL_API)) {
+		printf("Call to eglBindAPI() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	/* Select an appropriate configuration */
+	const EGLint configAttribs[] = {
+		EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+		EGL_BLUE_SIZE, 8,
+		EGL_GREEN_SIZE, 8,
+		EGL_RED_SIZE, 8,
+		EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+		EGL_NONE
+	};
+	EGLint numConfigs;
+	EGLConfig config;
+	if (!eglChooseConfig(dpy, configAttribs, &config, 1, &numConfigs)) {
+		printf("Call to eglChooseConfig() fails.\n");
+		return PIGLIT_FAIL;
+	}
+	if (numConfigs <= 0) {
+		printf("Call to eglChooseConfig() gave zero configs.\n");
+		return PIGLIT_SKIP;
+	}
+
+	const EGLint pbufferAttribs[] = {
+		EGL_WIDTH, WIDTH,
+		EGL_HEIGHT, WIDTH,
+		EGL_NONE
+	};
+	EGLSurface surf = eglCreatePbufferSurface(dpy, config, pbufferAttribs);
+	if (surf == EGL_NO_SURFACE) {
+		printf("Call to eglCreatePbufferSurface() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	/* Create a context */
+	EGLContext ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
+	if (EGL_NO_CONTEXT == ctx) {
+		printf("Call to eglCreateContext() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	/* Make the context current */
+	if (!eglMakeCurrent(dpy, surf, surf, ctx)) {
+		printf("Call to eglMakeCurrent() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	piglit_dispatch_default_init(PIGLIT_DISPATCH_GL);
+
+	/* Do the actual test */
+	if (PIGLIT_FAIL == commands())
+		return PIGLIT_FAIL;
+
+	if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+		printf("Call to eglMakeCurrent() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	if (!eglDestroySurface(dpy, surf)) {
+		printf("Call to eglDestroySurface() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	return PIGLIT_PASS;
+}
+
+
+static enum piglit_result
+surfaceless_test(EGLDisplay dpy)
+{
+	/* We are after desktop OpenGL - like requested in the config */
+	if (!eglBindAPI(EGL_OPENGL_API)) {
+		printf("Call to eglBindAPI() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	if (!piglit_is_egl_extension_supported(dpy, "EGL_KHR_surfaceless_context")) {
+		printf("No EGL_KHR_surfaceless_context available\n");
+		return PIGLIT_SKIP;
+	}
+
+	/* Select an appropriate configuration */
+	const EGLint configAttribs[] = {
+		EGL_SURFACE_TYPE, 0,
+		EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+		EGL_NONE
+	};
+	EGLint numConfigs;
+	EGLConfig config;
+	if (!eglChooseConfig(dpy, configAttribs, &config, 1, &numConfigs)) {
+		printf("Call to eglChooseConfig() fails.\n");
+		return PIGLIT_FAIL;
+	}
+	if (numConfigs <= 0) {
+		printf("Call to eglChooseConfig() gave zero configs.\n");
+		return PIGLIT_SKIP;
+	}
+
+	/* Create a context */
+	EGLContext ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
+	if (EGL_NO_CONTEXT == ctx) {
+		printf("Call to eglCreateContext() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	/* Make the context current */
+	if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
+		printf("Call to eglMakeCurrent() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	piglit_dispatch_default_init(PIGLIT_DISPATCH_GL);
+
+	/* Do the actual test */
+	if (PIGLIT_FAIL == commands_with_fbo())
+		return PIGLIT_FAIL;
+
+	if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+		printf("Call to eglMakeCurrent() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	return PIGLIT_PASS;
+}
+
+
+static enum piglit_result
+configless_test(EGLDisplay dpy)
+{
+	/* We are after desktop OpenGL - like requested in the config */
+	if (!eglBindAPI(EGL_OPENGL_API)) {
+		printf("Call to eglBindAPI() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	if (!piglit_is_egl_extension_supported(dpy, "EGL_KHR_no_config_context")) {
+		printf("No EGL_KHR_no_config_context available\n");
+		return PIGLIT_SKIP;
+	}
+	if (!piglit_is_egl_extension_supported(dpy, "EGL_KHR_surfaceless_context")) {
+		printf("No EGL_KHR_surfaceless_context available\n");
+		return PIGLIT_SKIP;
+	}
+
+	/* Create a context */
+	EGLContext ctx = eglCreateContext(dpy, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, NULL);
+	if (EGL_NO_CONTEXT == ctx) {
+		printf("Call to eglCreateContext() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	/* Make the context current */
+	if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
+		printf("Call to eglMakeCurrent() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	piglit_dispatch_default_init(PIGLIT_DISPATCH_GL);
+
+	/* Do the actual test */
+	if (PIGLIT_FAIL == commands_with_fbo())
+		return PIGLIT_FAIL;
+
+	if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+		printf("Call to eglMakeCurrent() fails.\n");
+		return PIGLIT_FAIL;
+	}
+
+	return PIGLIT_PASS;
+}
+
+
+static enum piglit_result
+for_all_device_displays(enum piglit_result (*call)(EGLDisplay))
+{
+#define NDEVS 1024
+	EGLDeviceEXT devices[NDEVS];
+	EGLint i, num_devices;
+	enum piglit_result result = PIGLIT_PASS;
+
+	if (!peglQueryDevicesEXT(NDEVS, devices, &num_devices)) {
+		printf("Failed to get egl device\n");
+		result = PIGLIT_FAIL;
+	}
+	if (num_devices <= 0) {
+		printf("Failed to get at least one egl device\n");
+		result = PIGLIT_FAIL;
+	}
+
+	/* For all available devices */
+	for (i = 0; i < num_devices; i++) {
+		EGLDisplay dpy;
+
+		printf("------------------------------------------------\n");
+		printf("Device #%d\n", i);
+		printf("------------------------------------------------\n");
+
+		/* Get a display from the device */
+		dpy = peglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT,
+						devices[i], NULL);
+		if (dpy == EGL_NO_DISPLAY) {
+			printf("Platform display shall not be EGL_NO_DISPLAY\n");
+			result = PIGLIT_FAIL;
+			continue;
+		}
+
+		/* Initialize the display */
+		EGLint major, minor;
+		if (!eglInitialize(dpy, &major, &minor)) {
+			printf("Call to eglInitialize() failed\n");
+			result = PIGLIT_FAIL;
+			continue;
+		}
+
+		/* Check the required EGL version */
+		if (major < 1 || (major == 1 && minor < 4)) {
+			printf("Call to eglInitialize() returned too low version\n");
+			result = PIGLIT_FAIL;
+		} else {
+			/* Do the actual test */
+			if (PIGLIT_FAIL == call(dpy))
+				result = PIGLIT_FAIL;
+		}
+
+		/* Tear down the display */
+		eglTerminate(dpy);
+	}
+
+	return result;
+}
+
+
+static enum piglit_result
+pbuffer_tests(void *test_data)
+{
+	printf("================================================\n");
+	printf("=============== PBUFFER ========================\n");
+	printf("================================================\n");
+
+	return for_all_device_displays(pbuffer_test);
+}
+
+
+static enum piglit_result
+surfaceless_tests(void *test_data)
+{
+	printf("================================================\n");
+	printf("=============== SURFACELESS ====================\n");
+	printf("================================================\n");
+
+	return for_all_device_displays(surfaceless_test);
+}
+
+
+static enum piglit_result
+configless_tests(void *test_data)
+{
+	printf("================================================\n");
+	printf("=============== CONFIGLESS =====================\n");
+	printf("================================================\n");
+
+	return for_all_device_displays(configless_test);
+}
+
+
+static const struct piglit_subtest subtests[] = {
+	{ "pbuffer_tests", "pbuffer_tests", pbuffer_tests },
+	{ "surfaceless_tests", "surfaceless_tests", surfaceless_tests },
+	{ "configless_tests", "configless_tests", configless_tests },
+	{ 0 },
+};
+
+
+int
+main(int argc, char **argv)
+{
+	enum piglit_result result = PIGLIT_SKIP;
+	const char **selected_names = NULL;
+	size_t num_selected = 0;
+
+#if _POSIX_C_SOURCE >= 200112L
+	unsetenv("DISPLAY");
+#endif
+
+	piglit_require_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_client_extensions");
+	piglit_require_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_device_base");
+	piglit_require_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_device_enumeration");
+	piglit_require_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_device_query");
+	piglit_require_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_platform_base");
+	piglit_require_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_platform_device");
+
+	/* Strip common piglit args. */
+	piglit_strip_arg(&argc, argv, "-fbo");
+	piglit_strip_arg(&argc, argv, "-auto");
+
+	piglit_parse_subtest_args(&argc, argv, subtests, &selected_names,
+				  &num_selected);
+
+	if (argc > 1) {
+		fprintf(stderr, "usage error\n");
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	init_egl_extension_funcs();
+	result = piglit_run_selected_subtests(subtests, selected_names,
+					      num_selected, result);
+
+	piglit_report_result(result);
+}
diff --git a/tests/opengl.py b/tests/opengl.py
index fb950d85d..93afdec8c 100644
--- a/tests/opengl.py
+++ b/tests/opengl.py
@@ -4647,6 +4647,12 @@  with profile.test_list.group_manager(
         exclude_platforms=['glx']) as g:
     g(['egl_ext_platform_device'], 'conformance')

+with profile.test_list.group_manager(
+        PiglitGLTest,
+        grouptools.join('spec', 'egl_ext_device_base'),
+        exclude_platforms=['glx']) as g:
+    g(['egl_ext_device_base'], 'conformance')
+
 with profile.test_list.group_manager(
         PiglitGLTest,
         grouptools.join('spec', 'egl_mesa_device_software'),

Comments


Marek,

> Reviewed-by: Marek Olšák <marek.olsak@amd.com>

Thanks for the review!
The patch is pushed now.

best

Mathias

> 
> Marek
> 
> On Wed, Apr 10, 2019 at 5:10 AM <Mathias.Froehlich@gmx.net> wrote:
> 
> > From: Mathias Fröhlich <mathias.froehlich@web.de>
> >
> > Hi all,
> >
> > Below is a new test that should test the about to be arriving egl device
> > extension. The test goes a bit further than just creating a context and
> > destroying it as it clears and paints into the buffer and checks the
> > result.
> >
> > This actually uncovers problems with the current egl implementation that
> > also show up with the new device extension.
> >
> > Please review
> > best
> >
> > Mathias
> >
> >
> >
> > The new test walks all available devices and makes sure that
> > context creation works as well as painting a rectangle.
> >
> > Signed-off-by: Mathias Froehlich <Mathias.Froehlich@web.de>
> > ---
> >  tests/egl/spec/CMakeLists.txt                 |   1 +
> >  .../egl_ext_device_base/CMakeLists.gl.txt     |   4 +
> >  .../spec/egl_ext_device_base/CMakeLists.txt   |   1 +
> >  .../egl_ext_device_base/egl_ext_device_base.c | 460 ++++++++++++++++++
> >  tests/opengl.py                               |   6 +
> >  5 files changed, 472 insertions(+)
> >  create mode 100644 tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt
> >  create mode 100644 tests/egl/spec/egl_ext_device_base/CMakeLists.txt
> >  create mode 100644
> > tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c
> >
> > diff --git a/tests/egl/spec/CMakeLists.txt b/tests/egl/spec/CMakeLists.txt
> > index 378c8d725..45a681b28 100644
> > --- a/tests/egl/spec/CMakeLists.txt
> > +++ b/tests/egl/spec/CMakeLists.txt
> > @@ -1,5 +1,6 @@
> >  add_subdirectory (egl-1.4)
> >  add_subdirectory (egl_ext_client_extensions)
> > +add_subdirectory (egl_ext_device_base)
> >  add_subdirectory (egl_ext_device_query)
> >  add_subdirectory (egl_ext_device_enumeration)
> >  add_subdirectory (egl_ext_device_drm)
> > diff --git a/tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt
> > b/tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt
> > new file mode 100644
> > index 000000000..2b65d07da
> > --- /dev/null
> > +++ b/tests/egl/spec/egl_ext_device_base/CMakeLists.gl.txt
> > @@ -0,0 +1,4 @@
> > +
> > +piglit_add_executable(egl_ext_device_base egl_ext_device_base.c)
> > +
> > +# vim: ft=cmake:
> > diff --git a/tests/egl/spec/egl_ext_device_base/CMakeLists.txt
> > b/tests/egl/spec/egl_ext_device_base/CMakeLists.txt
> > new file mode 100644
> > index 000000000..144a306f4
> > --- /dev/null
> > +++ b/tests/egl/spec/egl_ext_device_base/CMakeLists.txt
> > @@ -0,0 +1 @@
> > +piglit_include_target_api()
> > diff --git a/tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c
> > b/tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c
> > new file mode 100644
> > index 000000000..445f4f61c
> > --- /dev/null
> > +++ b/tests/egl/spec/egl_ext_device_base/egl_ext_device_base.c
> > @@ -0,0 +1,460 @@
> > +/*
> > + * Copyright 2019 Mathias Fröhlich <Mathias.Froehlich@web.de>.
> > + *
> > + * Copyright 2018 Collabora, Ltd.
> > + *
> > + * Based on ext_mesa_platform_surfaceless.c which has
> > + * Copyright 2016 Google
> > + *
> > + * 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.
> > + */
> > +
> > +/*
> > + * Test that enumerates all egl devices and tries to create an offscreen
> > buffer
> > + * for each device, does a bunch of gl calls on it and tears down the
> > objects
> > + * on the device again.
> > + */
> > +
> > +#include <stdlib.h>
> > +
> > +#include "piglit-util.h"
> > +#include "piglit-util-egl.h"
> > +#include "piglit-util-gl.h"
> > +
> > +
> > +#define WIDTH 16
> > +
> > +
> > +/* Extension function pointers.
> > + *
> > + * Use prefix 'pegl' (piglit egl) instead of 'egl' to avoid collisions
> > with
> > + * prototypes in eglext.h.
> > + */
> > +
> > +const char *(*peglQueryDeviceStringEXT)(EGLDeviceEXT device, EGLint name);
> > +EGLBoolean (*peglQueryDevicesEXT)(EGLint max_devices, EGLDeviceEXT
> > *devices,
> > +           EGLint *num_devices);
> > +EGLDisplay (*peglGetPlatformDisplayEXT)(EGLenum platform, void
> > *native_display,
> > +           const EGLint *attrib_list);
> > +
> > +static void
> > +init_egl_extension_funcs(void)
> > +{
> > +       peglQueryDeviceStringEXT = (void
> > *)eglGetProcAddress("eglQueryDeviceStringEXT");
> > +       peglQueryDevicesEXT = (void
> > *)eglGetProcAddress("eglQueryDevicesEXT");
> > +       peglGetPlatformDisplayEXT = (void
> > *)eglGetProcAddress("eglGetPlatformDisplayEXT");
> > +}
> > +
> > +
> > +static enum piglit_result
> > +commands()
> > +{
> > +       const GLfloat blue[3] = { 0, 0, 1 };
> > +       const GLfloat red[3] = { 1, 0, 0 };
> > +
> > +       printf("GL Vendor: %s\n", glGetString(GL_VENDOR));
> > +       printf("GL Renderer: %s\n", glGetString(GL_RENDERER));
> > +       printf("GL Version: %s\n", glGetString(GL_VERSION));
> > +
> > +       glClearColor(blue[0], blue[1], blue[2], 1);
> > +       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
> > +
> > +       if (!piglit_probe_pixel_rgb(WIDTH/2, WIDTH/2, blue)) {
> > +               printf("Pixel probe failed\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       glColor3fv(red);
> > +       piglit_draw_rect(-1, -1, 2, 2);
> > +
> > +       if (!piglit_probe_pixel_rgb(WIDTH/2, WIDTH/2, red)) {
> > +               printf("Pixel probe failed\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       if (!piglit_check_gl_error(0)) {
> > +               printf("Got OpenGL errors\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       return PIGLIT_PASS;
> > +}
> > +
> > +
> > +static enum piglit_result
> > +commands_with_fbo()
> > +{
> > +       enum piglit_result result;
> > +       GLuint fb, cb, db;
> > +       GLenum status;
> > +
> > +       if (!piglit_is_extension_supported("GL_ARB_framebuffer_object")) {
> > +               printf("No GL_ARB_framebuffer_object available\n");
> > +               return PIGLIT_SKIP;
> > +       }
> > +
> > +       glGenRenderbuffers(1, &cb);
> > +       glBindRenderbuffer(GL_RENDERBUFFER, cb);
> > +       glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, WIDTH, WIDTH);
> > +       glBindRenderbuffer(GL_RENDERBUFFER, 0);
> > +
> > +       glGenRenderbuffers(1, &db);
> > +       glBindRenderbuffer(GL_RENDERBUFFER, db);
> > +       glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, WIDTH,
> > WIDTH);
> > +       glBindRenderbuffer(GL_RENDERBUFFER, 0);
> > +
> > +       glGenFramebuffers(1, &fb);
> > +       glBindFramebuffer(GL_FRAMEBUFFER, fb);
> > +       glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
> > GL_RENDERBUFFER, cb);
> > +       glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
> > GL_RENDERBUFFER, db);
> > +
> > +       status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
> > +       if (status != GL_FRAMEBUFFER_COMPLETE) {
> > +               printf("FBO incomplete status 0x%X\n", status);
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       glViewport(0, 0, WIDTH, WIDTH);
> > +
> > +       result = commands();
> > +
> > +       glDeleteFramebuffers(1, &fb);
> > +       glDeleteRenderbuffers(1, &cb);
> > +       glDeleteRenderbuffers(1, &db);
> > +
> > +       return result;
> > +}
> > +
> > +
> > +static enum piglit_result
> > +pbuffer_test(EGLDisplay dpy)
> > +{
> > +       /* We are after desktop OpenGL - like requested in the config */
> > +       if (!eglBindAPI(EGL_OPENGL_API)) {
> > +               printf("Call to eglBindAPI() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       /* Select an appropriate configuration */
> > +       const EGLint configAttribs[] = {
> > +               EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
> > +               EGL_BLUE_SIZE, 8,
> > +               EGL_GREEN_SIZE, 8,
> > +               EGL_RED_SIZE, 8,
> > +               EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
> > +               EGL_NONE
> > +       };
> > +       EGLint numConfigs;
> > +       EGLConfig config;
> > +       if (!eglChooseConfig(dpy, configAttribs, &config, 1, &numConfigs))
> > {
> > +               printf("Call to eglChooseConfig() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +       if (numConfigs <= 0) {
> > +               printf("Call to eglChooseConfig() gave zero configs.\n");
> > +               return PIGLIT_SKIP;
> > +       }
> > +
> > +       const EGLint pbufferAttribs[] = {
> > +               EGL_WIDTH, WIDTH,
> > +               EGL_HEIGHT, WIDTH,
> > +               EGL_NONE
> > +       };
> > +       EGLSurface surf = eglCreatePbufferSurface(dpy, config,
> > pbufferAttribs);
> > +       if (surf == EGL_NO_SURFACE) {
> > +               printf("Call to eglCreatePbufferSurface() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       /* Create a context */
> > +       EGLContext ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT,
> > NULL);
> > +       if (EGL_NO_CONTEXT == ctx) {
> > +               printf("Call to eglCreateContext() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       /* Make the context current */
> > +       if (!eglMakeCurrent(dpy, surf, surf, ctx)) {
> > +               printf("Call to eglMakeCurrent() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       piglit_dispatch_default_init(PIGLIT_DISPATCH_GL);
> > +
> > +       /* Do the actual test */
> > +       if (PIGLIT_FAIL == commands())
> > +               return PIGLIT_FAIL;
> > +
> > +       if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
> > EGL_NO_CONTEXT)) {
> > +               printf("Call to eglMakeCurrent() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       if (!eglDestroySurface(dpy, surf)) {
> > +               printf("Call to eglDestroySurface() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       return PIGLIT_PASS;
> > +}
> > +
> > +
> > +static enum piglit_result
> > +surfaceless_test(EGLDisplay dpy)
> > +{
> > +       /* We are after desktop OpenGL - like requested in the config */
> > +       if (!eglBindAPI(EGL_OPENGL_API)) {
> > +               printf("Call to eglBindAPI() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       if (!piglit_is_egl_extension_supported(dpy,
> > "EGL_KHR_surfaceless_context")) {
> > +               printf("No EGL_KHR_surfaceless_context available\n");
> > +               return PIGLIT_SKIP;
> > +       }
> > +
> > +       /* Select an appropriate configuration */
> > +       const EGLint configAttribs[] = {
> > +               EGL_SURFACE_TYPE, 0,
> > +               EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
> > +               EGL_NONE
> > +       };
> > +       EGLint numConfigs;
> > +       EGLConfig config;
> > +       if (!eglChooseConfig(dpy, configAttribs, &config, 1, &numConfigs))
> > {
> > +               printf("Call to eglChooseConfig() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +       if (numConfigs <= 0) {
> > +               printf("Call to eglChooseConfig() gave zero configs.\n");
> > +               return PIGLIT_SKIP;
> > +       }
> > +
> > +       /* Create a context */
> > +       EGLContext ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT,
> > NULL);
> > +       if (EGL_NO_CONTEXT == ctx) {
> > +               printf("Call to eglCreateContext() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       /* Make the context current */
> > +       if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
> > +               printf("Call to eglMakeCurrent() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       piglit_dispatch_default_init(PIGLIT_DISPATCH_GL);
> > +
> > +       /* Do the actual test */
> > +       if (PIGLIT_FAIL == commands_with_fbo())
> > +               return PIGLIT_FAIL;
> > +
> > +       if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
> > EGL_NO_CONTEXT)) {
> > +               printf("Call to eglMakeCurrent() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       return PIGLIT_PASS;
> > +}
> > +
> > +
> > +static enum piglit_result
> > +configless_test(EGLDisplay dpy)
> > +{
> > +       /* We are after desktop OpenGL - like requested in the config */
> > +       if (!eglBindAPI(EGL_OPENGL_API)) {
> > +               printf("Call to eglBindAPI() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       if (!piglit_is_egl_extension_supported(dpy,
> > "EGL_KHR_no_config_context")) {
> > +               printf("No EGL_KHR_no_config_context available\n");
> > +               return PIGLIT_SKIP;
> > +       }
> > +       if (!piglit_is_egl_extension_supported(dpy,
> > "EGL_KHR_surfaceless_context")) {
> > +               printf("No EGL_KHR_surfaceless_context available\n");
> > +               return PIGLIT_SKIP;
> > +       }
> > +
> > +       /* Create a context */
> > +       EGLContext ctx = eglCreateContext(dpy, EGL_NO_CONFIG_KHR,
> > EGL_NO_CONTEXT, NULL);
> > +       if (EGL_NO_CONTEXT == ctx) {
> > +               printf("Call to eglCreateContext() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       /* Make the context current */
> > +       if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
> > +               printf("Call to eglMakeCurrent() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       piglit_dispatch_default_init(PIGLIT_DISPATCH_GL);
> > +
> > +       /* Do the actual test */
> > +       if (PIGLIT_FAIL == commands_with_fbo())
> > +               return PIGLIT_FAIL;
> > +
> > +       if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
> > EGL_NO_CONTEXT)) {
> > +               printf("Call to eglMakeCurrent() fails.\n");
> > +               return PIGLIT_FAIL;
> > +       }
> > +
> > +       return PIGLIT_PASS;
> > +}
> > +
> > +
> > +static enum piglit_result
> > +for_all_device_displays(enum piglit_result (*call)(EGLDisplay))
> > +{
> > +#define NDEVS 1024
> > +       EGLDeviceEXT devices[NDEVS];
> > +       EGLint i, num_devices;
> > +       enum piglit_result result = PIGLIT_PASS;
> > +
> > +       if (!peglQueryDevicesEXT(NDEVS, devices, &num_devices)) {
> > +               printf("Failed to get egl device\n");
> > +               result = PIGLIT_FAIL;
> > +       }
> > +       if (num_devices <= 0) {
> > +               printf("Failed to get at least one egl device\n");
> > +               result = PIGLIT_FAIL;
> > +       }
> > +
> > +       /* For all available devices */
> > +       for (i = 0; i < num_devices; i++) {
> > +               EGLDisplay dpy;
> > +
> > +
> >  printf("------------------------------------------------\n");
> > +               printf("Device #%d\n", i);
> > +
> >  printf("------------------------------------------------\n");
> > +
> > +               /* Get a display from the device */
> > +               dpy = peglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT,
> > +                                               devices[i], NULL);
> > +               if (dpy == EGL_NO_DISPLAY) {
> > +                       printf("Platform display shall not be
> > EGL_NO_DISPLAY\n");
> > +                       result = PIGLIT_FAIL;
> > +                       continue;
> > +               }
> > +
> > +               /* Initialize the display */
> > +               EGLint major, minor;
> > +               if (!eglInitialize(dpy, &major, &minor)) {
> > +                       printf("Call to eglInitialize() failed\n");
> > +                       result = PIGLIT_FAIL;
> > +                       continue;
> > +               }
> > +
> > +               /* Check the required EGL version */
> > +               if (major < 1 || (major == 1 && minor < 4)) {
> > +                       printf("Call to eglInitialize() returned too low
> > version\n");
> > +                       result = PIGLIT_FAIL;
> > +               } else {
> > +                       /* Do the actual test */
> > +                       if (PIGLIT_FAIL == call(dpy))
> > +                               result = PIGLIT_FAIL;
> > +               }
> > +
> > +               /* Tear down the display */
> > +               eglTerminate(dpy);
> > +       }
> > +
> > +       return result;
> > +}
> > +
> > +
> > +static enum piglit_result
> > +pbuffer_tests(void *test_data)
> > +{
> > +       printf("================================================\n");
> > +       printf("=============== PBUFFER ========================\n");
> > +       printf("================================================\n");
> > +
> > +       return for_all_device_displays(pbuffer_test);
> > +}
> > +
> > +
> > +static enum piglit_result
> > +surfaceless_tests(void *test_data)
> > +{
> > +       printf("================================================\n");
> > +       printf("=============== SURFACELESS ====================\n");
> > +       printf("================================================\n");
> > +
> > +       return for_all_device_displays(surfaceless_test);
> > +}
> > +
> > +
> > +static enum piglit_result
> > +configless_tests(void *test_data)
> > +{
> > +       printf("================================================\n");
> > +       printf("=============== CONFIGLESS =====================\n");
> > +       printf("================================================\n");
> > +
> > +       return for_all_device_displays(configless_test);
> > +}
> > +
> > +
> > +static const struct piglit_subtest subtests[] = {
> > +       { "pbuffer_tests", "pbuffer_tests", pbuffer_tests },
> > +       { "surfaceless_tests", "surfaceless_tests", surfaceless_tests },
> > +       { "configless_tests", "configless_tests", configless_tests },
> > +       { 0 },
> > +};
> > +
> > +
> > +int
> > +main(int argc, char **argv)
> > +{
> > +       enum piglit_result result = PIGLIT_SKIP;
> > +       const char **selected_names = NULL;
> > +       size_t num_selected = 0;
> > +
> > +#if _POSIX_C_SOURCE >= 200112L
> > +       unsetenv("DISPLAY");
> > +#endif
> > +
> > +       piglit_require_egl_extension(EGL_NO_DISPLAY,
> > "EGL_EXT_client_extensions");
> > +       piglit_require_egl_extension(EGL_NO_DISPLAY,
> > "EGL_EXT_device_base");
> > +       piglit_require_egl_extension(EGL_NO_DISPLAY,
> > "EGL_EXT_device_enumeration");
> > +       piglit_require_egl_extension(EGL_NO_DISPLAY,
> > "EGL_EXT_device_query");
> > +       piglit_require_egl_extension(EGL_NO_DISPLAY,
> > "EGL_EXT_platform_base");
> > +       piglit_require_egl_extension(EGL_NO_DISPLAY,
> > "EGL_EXT_platform_device");
> > +
> > +       /* Strip common piglit args. */
> > +       piglit_strip_arg(&argc, argv, "-fbo");
> > +       piglit_strip_arg(&argc, argv, "-auto");
> > +
> > +       piglit_parse_subtest_args(&argc, argv, subtests, &selected_names,
> > +                                 &num_selected);
> > +
> > +       if (argc > 1) {
> > +               fprintf(stderr, "usage error\n");
> > +               piglit_report_result(PIGLIT_FAIL);
> > +       }
> > +
> > +       init_egl_extension_funcs();
> > +       result = piglit_run_selected_subtests(subtests, selected_names,
> > +                                             num_selected, result);
> > +
> > +       piglit_report_result(result);
> > +}
> > diff --git a/tests/opengl.py b/tests/opengl.py
> > index fb950d85d..93afdec8c 100644
> > --- a/tests/opengl.py
> > +++ b/tests/opengl.py
> > @@ -4647,6 +4647,12 @@ with profile.test_list.group_manager(
> >          exclude_platforms=['glx']) as g:
> >      g(['egl_ext_platform_device'], 'conformance')
> >
> > +with profile.test_list.group_manager(
> > +        PiglitGLTest,
> > +        grouptools.join('spec', 'egl_ext_device_base'),
> > +        exclude_platforms=['glx']) as g:
> > +    g(['egl_ext_device_base'], 'conformance')
> > +
> >  with profile.test_list.group_manager(
> >          PiglitGLTest,
> >          grouptools.join('spec', 'egl_mesa_device_software'),
> > --
> > 2.20.1
> >
> >
>