[Piglit] [PATCH v2] new test: glx-multithread-texture.

Frank Henigman fjhenigman at google.com
Wed Jun 12 08:31:45 PDT 2013


New test for loading texture data from one thread and context while drawing
with those textures from another thread and shared context.  The threads are
synchronized so they do not attempt to use the same texture at the same time.

v2
- use MIT license
- fix formatting
- correct float pixel value is integer/255, not integer/256
- may not have alpha channel, so don't probe it
- sleep to prevent starvation
- passes on pineview with intel driver and nvidia

Signed-off-by: Frank Henigman <fjhenigman at google.com>
---
 tests/all.tests                     |   1 +
 tests/glx/CMakeLists.gl.txt         |   2 +
 tests/glx/glx-multithread-texture.c | 266 ++++++++++++++++++++++++++++++++++++
 3 files changed, 269 insertions(+)
 create mode 100644 tests/glx/glx-multithread-texture.c

diff --git a/tests/all.tests b/tests/all.tests
index 382f510..d71f0e1 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -364,6 +364,7 @@ glx['glx-fbconfig-compliance'].runConcurrent = True
 add_plain_test(glx, 'glx-fbo-binding')
 add_plain_test(glx, 'glx-multi-context-ib-1')
 add_plain_test(glx, 'glx-multithread')
+add_plain_test(glx, 'glx-multithread-texture')
 add_plain_test(glx, 'glx-multithread-makecurrent-1')
 add_plain_test(glx, 'glx-multithread-makecurrent-2')
 add_plain_test(glx, 'glx-multithread-makecurrent-3')
diff --git a/tests/glx/CMakeLists.gl.txt b/tests/glx/CMakeLists.gl.txt
index ca85317..03fee75 100644
--- a/tests/glx/CMakeLists.gl.txt
+++ b/tests/glx/CMakeLists.gl.txt
@@ -33,6 +33,8 @@ IF(PIGLIT_BUILD_GLX_TESTS)
 	piglit_add_executable (glx-multi-context-ib-1 glx-multi-context-ib-1.c)
 	piglit_add_executable (glx-multithread glx-multithread.c)
 	target_link_libraries(glx-multithread pthread)
+	piglit_add_executable (glx-multithread-texture glx-multithread-texture.c)
+	target_link_libraries(glx-multithread-texture pthread)
 	piglit_add_executable (glx-multithread-makecurrent-1 glx-multithread-makecurrent-1.c)
 	target_link_libraries(glx-multithread-makecurrent-1 pthread)
 	piglit_add_executable (glx-multithread-makecurrent-2 glx-multithread-makecurrent-2.c)
diff --git a/tests/glx/glx-multithread-texture.c b/tests/glx/glx-multithread-texture.c
new file mode 100644
index 0000000..5104723
--- /dev/null
+++ b/tests/glx/glx-multithread-texture.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * 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 glx-multithread-texture.c
+ *
+ * Test loading texture data from one thread and context while drawing with
+ * those textures from another thread and shared context.  The threads are
+ * synchronized so they do not attempt to use the same texture at the same time.
+ */
+
+#include <unistd.h>
+
+#include "piglit-util-gl-common.h"
+#include "piglit-glx-util.h"
+#include "pthread.h"
+
+int piglit_width = 50, piglit_height = 50;
+static int tex_width = 512, tex_height = 512;
+static unsigned num_test = 300;
+static bool quit = false;
+
+static Display *dpy;
+static Window draw_win;
+static GLXPixmap load_win;
+static pthread_mutex_t mutex;
+static XVisualInfo *visinfo;
+static GLXContext draw_ctx, load_ctx;
+
+/*
+ * list of textures
+ *
+ * user == DRAW means draw thread may draw with this texture
+ * user == LOAD means load thread may load data into this texture
+ * user == NONE means texture not in use and may be claimed by either thread
+ *
+ * Minimum of three items needed in this array for the code to work.
+ */
+static struct texture {
+	GLuint id;
+	int color;
+	enum user { DRAW, LOAD, NONE } user;
+} texture[5];
+
+/*
+ * If texture at *pos is not in use claim it for 'user' and increment *pos.
+ * Return texture at *pos.
+ */
+static struct texture *
+advance(int *pos, enum user user)
+{
+	int cur = *pos % ARRAY_SIZE(texture);
+	int next = (cur + 1) % ARRAY_SIZE(texture);
+
+	pthread_mutex_lock(&mutex);
+	assert(texture[cur].user == user);
+	if (texture[next].user == NONE) {
+		texture[cur].user = NONE;
+		cur = next;
+		*pos += 1;
+		texture[cur].user = user;
+	}
+	pthread_mutex_unlock(&mutex);
+
+	/* helps avoid starvation */
+	usleep(1);
+
+	return texture + cur;
+}
+
+/*
+ * Texture writing thread: loads data into successive textures, taking note
+ * of what color was used so it can be checked later.
+ * Return NULL on failure, else non-NULL.
+ */
+static void *
+load_func(void *arg)
+{
+	int count = 1;
+	struct texture *tex = texture + count;
+	unsigned int tex_bytes = tex_width * tex_height * 4;
+	unsigned char *tex_data = malloc(tex_bytes);
+	int ret;
+
+	ret = glXMakeCurrent(dpy, load_win, load_ctx);
+	assert(ret);
+
+	glEnable(GL_TEXTURE_2D);
+
+	while (!quit && count <= num_test) {
+		int color = count & 0xff;
+
+		assert(tex->user == LOAD);
+		if (tex->color != color) {
+			memset(tex_data, color, tex_bytes);
+			tex->color = color;
+		}
+		glBindTexture(GL_TEXTURE_2D, tex->id);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height,
+			     0, GL_RGBA, GL_UNSIGNED_BYTE, tex_data);
+
+		tex = advance(&count, LOAD);
+	}
+
+	glFinish();
+	free(tex_data);
+
+	if (count <= num_test) {
+		quit = true;
+		return NULL;
+	}
+
+	return "";
+}
+
+/*
+ * Texture using thread: draws with successive textures and checks that the
+ * correct color is drawn.  Return NULL on failure, else non-NULL.
+ */
+static void *
+draw_func(void *arg)
+{
+	int count = 0;
+	int ret;
+
+	ret = glXMakeCurrent(dpy, draw_win, draw_ctx);
+	assert(ret);
+
+	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
+
+	glEnable(GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+	while (!quit && count < num_test) {
+		struct texture *tex = advance(&count, DRAW);
+		float expect[] = {
+			tex->color / 255.,
+			tex->color / 255.,
+			tex->color / 255.,
+		};
+
+		assert(tex->user == DRAW);
+
+		glBindTexture(GL_TEXTURE_2D, tex->id);
+		piglit_draw_rect_tex(0, 0, piglit_width, piglit_height,
+				     0, 0, 1, 1);
+		glXSwapBuffers(dpy, draw_win);
+
+		/* first texture not filled so don't check it */
+		if (count > 0 &&
+			!piglit_probe_rect_rgb(0, 0, piglit_width,
+					       piglit_height, expect)) {
+			break;
+		}
+	}
+
+	if (count < num_test) {
+		quit = true;
+		return NULL;
+	}
+
+	return "";
+}
+
+enum piglit_result
+draw(Display *dpy)
+{
+	pthread_t draw_thread, load_thread;
+	void *draw_ret, *load_ret;
+	int ret, i;
+	GLXContext my_ctx;
+
+	my_ctx = piglit_get_glx_context_share(dpy, visinfo, NULL);
+	draw_ctx = piglit_get_glx_context_share(dpy, visinfo, my_ctx);
+	load_ctx = piglit_get_glx_context_share(dpy, visinfo, my_ctx);
+
+	ret = glXMakeCurrent(dpy, draw_win, my_ctx);
+	assert(ret);
+	piglit_dispatch_default_init();
+
+	glEnable(GL_TEXTURE_2D);
+
+	for (i = 0; i < ARRAY_SIZE(texture); ++i) {
+		glGenTextures(1, &texture[i].id);
+		texture[i].color = -1;
+		texture[i].user = NONE;
+		glBindTexture(GL_TEXTURE_2D, texture[i].id);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+				GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+				GL_NEAREST);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height,
+			     0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+	}
+	texture[0].user = DRAW;
+	texture[1].user = LOAD;
+
+	pthread_mutex_init(&mutex, NULL);
+
+	pthread_create(&draw_thread, NULL, draw_func, NULL);
+	pthread_create(&load_thread, NULL, load_func, NULL);
+
+	ret = pthread_join(draw_thread, &draw_ret);
+	assert(ret == 0);
+	ret = pthread_join(load_thread, &load_ret);
+	assert(ret == 0);
+
+	pthread_mutex_destroy(&mutex);
+
+	glXDestroyContext(dpy, load_ctx);
+	glXDestroyContext(dpy, draw_ctx);
+	glXDestroyContext(dpy, my_ctx);
+
+	return draw_ret && load_ret ? PIGLIT_PASS : PIGLIT_FAIL;
+}
+
+int
+main(int argc, char **argv)
+{
+	int i;
+	Pixmap pixmap;
+
+	for(i = 1; i < argc; ++i) {
+		if (!strcmp(argv[i], "-auto"))
+			piglit_automatic = 1;
+		else
+			fprintf(stderr, "Unknown option: %s\n", argv[i]);
+	}
+
+	XInitThreads();
+	dpy = XOpenDisplay(NULL);
+	if (dpy == NULL) {
+		fprintf(stderr, "couldn't open display\n");
+		piglit_report_result(PIGLIT_FAIL);
+	}
+	visinfo = piglit_get_glx_visual(dpy);
+	draw_win = piglit_get_glx_window(dpy, visinfo);
+	pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
+		piglit_width, piglit_height, visinfo->depth);
+	load_win = glXCreateGLXPixmap(dpy, visinfo, pixmap);
+
+	XMapWindow(dpy, draw_win);
+
+	piglit_glx_event_loop(dpy, draw);
+
+	return 0;
+}
-- 
1.8.3



More information about the Piglit mailing list