[Piglit] [PATCH] new test: glx-multithread-texture.
Frank Henigman
fjhenigman at google.com
Mon Jun 10 13:36:20 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.
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
+ */
+
+/** @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) {
+ 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;
+}
--
1.8.3
More information about the Piglit
mailing list