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

Brian Paul brianp at vmware.com
Tue Jun 11 08:25:11 PDT 2013


On 06/10/2013 02:36 PM, Frank Henigman wrote:
> 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.
>
> 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 | 253 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 256 insertions(+)
>   create mode 100644 tests/glx/glx-multithread-texture.c
>
> diff --git a/tests/all.tests b/tests/all.tests
> index 73f08f4..60f10d1 100644
> --- a/tests/all.tests
> +++ b/tests/all.tests
> @@ -348,6 +348,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..dbf337f
> --- /dev/null
> +++ b/tests/glx/glx-multithread-texture.c
> @@ -0,0 +1,253 @@
> +/*
> + * Copyright 2013 Google Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
> + */

Most piglit tests use a MIT-style license (see COPYING).  Is there a 
particular reason for GPL?


> +
> +/** @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 "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.
> + */
> +struct texture *advance(int *pos, enum user user) {

formatting (to match rest of code):

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);
> +	return texture + cur;
> +}
> +
> +/*
> + * Load successive textures, taking note of what color is loaded 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 "";
> +}
> +
> +/*
> + * Draw successive textures and check 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 / 256.,
> +			tex->color / 256.,
> +			tex->color / 256.,
> +			tex->color / 256.,
> +		};
> +
> +		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_rgba(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;
> +}
>

Reviewed-by: Brian Paul <brianp at vmware.com>

But when I run with NVIDIA's driver I get a failure:

bin/glx-multithread-texture -auto
Probe at (0,0)
   Expected: 0.003906 0.003906 0.003906 0.003906
   Observed: 0.003922 0.003922 0.003922 1.000000
PIGLIT: {'result': 'fail' }

-Brian



More information about the Piglit mailing list