[1/7] tests: Add base test for mid-command preemption.

Submitted by Rafael Antognolli on Oct. 4, 2018, 3:35 p.m.

Details

Message ID 20181004153535.17863-2-rafael.antognolli@intel.com
State New
Headers show
Series "New preemption test." ( rev: 1 ) in Piglit

Not browsing as part of any series.

Commit Message

Rafael Antognolli Oct. 4, 2018, 3:35 p.m.
This is the base of the test, where we use the main piglit context to
render to the framebuffer. It is supposed to be an artificially slow
draw call, that can be preempted by a higher priority context if needed.
---
 tests/egl/CMakeLists.gl.txt        |   2 +
 tests/egl/egl-context-preemption.c | 319 +++++++++++++++++++++++++++++
 2 files changed, 321 insertions(+)
 create mode 100644 tests/egl/egl-context-preemption.c

Patch hide | download patch | download mbox

diff --git a/tests/egl/CMakeLists.gl.txt b/tests/egl/CMakeLists.gl.txt
index 3691c56a9..6de166044 100644
--- a/tests/egl/CMakeLists.gl.txt
+++ b/tests/egl/CMakeLists.gl.txt
@@ -35,6 +35,8 @@  IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 	target_link_libraries(egl-invalid-attr pthread)
 	piglit_add_executable (egl-context-priority egl-context-priority.c)
 	target_link_libraries(egl-context-priority pthread)
+	piglit_add_executable (egl-context-preemption egl-context-preemption.c)
+	target_link_libraries(egl-context-preemption pthread)
 ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 
 # vim: ft=cmake:
diff --git a/tests/egl/egl-context-preemption.c b/tests/egl/egl-context-preemption.c
new file mode 100644
index 000000000..82a698aa1
--- /dev/null
+++ b/tests/egl/egl-context-preemption.c
@@ -0,0 +1,319 @@ 
+/*
+ * Copyright © 2018 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.
+ */
+
+#include "piglit-util-egl.h"
+#include "piglit-util-gl.h"
+
+#include <pthread.h>
+
+#include <inttypes.h>
+
+/**
+ * @file egl-context-preemption.c
+ *
+ * EGL API tests for IMG_context_priority extension:
+ * https://www.khronos.org/registry/EGL/extensions/IMG/EGL_IMG_context_priority.txt
+ *
+ * This file tries to test mid-command preemption (between triangles) support
+ * through the IMG_context_priority extension.  Particularly on i965, if a
+ * context is marked with high priority level, then it should preempt lower
+ * priority contexts (when the hardware and kernel supports it).
+ */
+
+#define HIGH_PRIO_RUNS 50
+
+struct test_data {
+	bool main_finished;
+	int64_t main_tstarted, main_tfinished;
+	EGLDisplay dpy;
+};
+
+struct test_profile {
+	GLfloat *vertices;
+	size_t bufsize;
+	GLenum draw_mode;
+	GLuint (*shader_setup)(void);
+};
+
+static bool small = false;
+static int total_objects = 0;
+
+static const char *vs_text =
+	"#version 330 core\n"
+	"layout (location = 0) in vec3 aPos;\n"
+	"uniform int nInstances;\n"
+	"out vec4 color;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"    int i = gl_InstanceID;\n"
+	"    float integer;\n"
+	"    float r = 0.0 + (1.0 / nInstances) * i;\n"
+	"    modf(r, integer);\n"
+	"    r -= integer;\n"
+	"    float g = 0.333 + (1.0 / nInstances) * i;\n"
+	"    modf(g, integer);\n"
+	"    g -= integer;\n"
+	"    float b = 0.666 + (1.0 / nInstances) * i;\n"
+	"    modf(b, integer);\n"
+	"    b -= integer;\n"
+	"    color = vec4(r, g, b, 0.8);\n"
+	"    float invertz = mod(i, 2) * 2 - 1.0;\n"
+	"\n"
+	"    float width = 2.0;\n"
+	"    float dx = (2.0 / nInstances) * i - 1;\n"
+	"    gl_Position = vec4(aPos.x + dx, aPos.y, i / nInstances, 1.0);\n"
+	"}\n";
+
+
+static const char *fs_text =
+	"#version 330 core\n"
+	"in vec4 color;\n"
+	"out vec4 FragColor;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"    FragColor = color;\n"
+	"}\n";
+
+static GLuint setup_shaders(void)
+{
+	GLuint prog = piglit_build_simple_program(vs_text, fs_text);
+
+	glUseProgram(prog);
+
+	return prog;
+}
+
+#define MAX_OBJECTS 1000000
+
+static GLfloat triangle_vertices[] = {
+	-1.0f, -1.0f, 0.0f,
+	0.0f, 1.0f, 0.0f,
+	1.0f, -1.0f, 0.0f,
+};
+
+/* 3 vertices for the first triangle, plus 1 more fore each triangle (4
+ * triangles in total)
+ */
+static GLfloat trifan_vertices[] = {
+	0.0f, 0.0f, 0.0f,
+	1.0f, -1.0f, 0.0f,
+	-1.0f, -1.0f, 0.0f,
+	-1.0f, 1.0f, 0.0f,
+	1.0f, 1.0f, 0.0f,
+	1.0f, -1.0f, 0.0f,
+};
+
+static void
+draw_objects(unsigned int shader_program, GLenum mode, GLfloat *vertices,
+	     int bufsize, int n_instances)
+{
+
+	glClearColor(1, 1, 1, 1);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	int nInstancesLocation = glGetUniformLocation(shader_program, "nInstances");
+	glUseProgram(shader_program);
+	glUniform1i(nInstancesLocation, n_instances);
+
+	// This will identify our vertex buffer
+	GLuint vertexbuffer;
+	// Generate 1 buffer, put the resulting identifier in vertexbuffer
+	glGenBuffers(1, &vertexbuffer);
+	// The following commands will talk about our 'vertexbuffer' buffer
+	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
+	// Give our vertices to OpenGL.
+	glBufferData(GL_ARRAY_BUFFER, bufsize,
+		     vertices, GL_STATIC_DRAW);
+
+	// 1st attribute buffer : vertices
+	glEnableVertexAttribArray(0);
+	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
+	glVertexAttribPointer(
+		0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
+		3,                  // size
+		GL_FLOAT,           // type
+		GL_FALSE,           // normalized?
+		0,                  // stride
+		(void*)0            // array buffer offset
+		);
+	// Draw the triangle!
+	glDrawArraysInstanced(mode, 0, bufsize / sizeof(GLfloat), n_instances);
+	glDisableVertexAttribArray(0);
+}
+
+static GLfloat *
+read_pixels_float(GLint x, GLint y, GLsizei width, GLsizei height,
+		  GLenum format, GLfloat *pixels)
+{
+	GLubyte *pixels_b;
+	unsigned i, j, k;
+	int comps = piglit_num_components(format);
+
+	if (!pixels)
+		pixels = malloc(width * height * comps * sizeof(GLfloat));
+
+	if (!piglit_is_gles()) {
+		glReadPixels(x, y, width, height, format, GL_FLOAT, pixels);
+		return pixels;
+	}
+
+	pixels_b = malloc(width * height * 4 * sizeof(GLubyte));
+	glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels_b);
+	k = 0;
+	for (i = 0; i < width * height; i++) {
+		for (j = 0; j < comps; j++) {
+			pixels[k++] = pixels_b[i*4+j] / 255.0f;
+		}
+	}
+	free(pixels_b);
+	return pixels;
+}
+
+static enum piglit_result
+test_preemption(void *data)
+{
+	enum piglit_result result = PIGLIT_PASS;
+	const struct test_profile *profile = data;
+	struct test_data d = {
+		.main_finished = false,
+	};
+	d.dpy = eglGetCurrentDisplay();
+
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo);
+
+	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+		piglit_loge("ERROR::FRAMEBUFFER:: Framebuffer is not complete!\n");
+
+	unsigned int program = profile->shader_setup();
+
+	GLuint VertexArrayID;
+	glGenVertexArrays(1, &VertexArrayID);
+	glBindVertexArray(VertexArrayID);
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	const int divisor = small ? 10 : 1;
+	glViewport(0, 0, piglit_width / divisor, piglit_height / divisor);
+	/* Draw baseline into fb */
+	draw_objects(program, profile->draw_mode,
+		     profile->vertices, profile->bufsize, total_objects);
+	glFinish();
+
+	float *ref_image = NULL;
+	ref_image = read_pixels_float(0, 0, piglit_width, piglit_height,
+				      GL_RGBA, NULL);
+
+	/* Draw real image into fb */
+	draw_objects(program, profile->draw_mode,
+		     profile->vertices, profile->bufsize, total_objects);
+	glFlush();
+
+	GLuint query;
+	glGenQueries(1, &query);
+	glGetInteger64v(GL_TIMESTAMP, &d.main_tstarted);
+	glQueryCounter(query, GL_TIMESTAMP);
+
+	glFinish();
+	glGetQueryObjecti64v(query, GL_QUERY_RESULT, &d.main_tfinished);
+	d.main_finished = true;
+
+	bool pass;
+	pass = piglit_probe_image_rgba(0, 0, piglit_width, piglit_height, ref_image);
+	if (!pass) {
+		result = PIGLIT_FAIL;
+		goto cleanup;
+	}
+
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+cleanup:
+	free(ref_image);
+	return result;
+}
+
+static struct test_profile triangles = {
+	.vertices = triangle_vertices,
+	.bufsize = sizeof(triangle_vertices),
+	.draw_mode = GL_TRIANGLES,
+	.shader_setup = setup_shaders,
+};
+
+static struct test_profile trifan = {
+	.vertices = trifan_vertices,
+	.bufsize = sizeof(trifan_vertices),
+	.draw_mode = GL_TRIANGLE_FAN,
+	.shader_setup = setup_shaders,
+};
+
+static const struct piglit_subtest subtests[] = {
+	{
+		"triangles",
+		"triangles",
+		test_preemption,
+		&triangles,
+	},
+	{
+		"trifan",
+		"trifan",
+		test_preemption,
+		&trifan,
+	},
+	{0},
+};
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+	config.supports_gl_core_version = 32;
+	config.window_width = 800;
+	config.window_height = 600;
+	config.subtests = subtests;
+PIGLIT_GL_TEST_CONFIG_END
+
+enum piglit_result
+piglit_display(void)
+{
+	enum piglit_result result = PIGLIT_SKIP;
+	const char **selected_subtests = NULL;
+	size_t num_subtests = piglit_get_selected_tests(&selected_subtests);
+	result = piglit_run_selected_subtests(subtests, selected_subtests,
+					      num_subtests, result);
+	piglit_present_results();
+
+	return result;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	EGLDisplay dpy;
+
+	dpy = eglGetCurrentDisplay();
+	piglit_require_egl_extension(dpy, "EGL_IMG_context_priority");
+
+	if (piglit_strip_arg(&argc, argv, "small"))
+		small = true;
+
+	total_objects = small ? MAX_OBJECTS : 10000;
+}