2 * Copyright 2013 Google Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 /** @file glx-multithread-texture.c
26 * Test loading texture data from one thread and context while drawing with
27 * those textures from another thread and shared context. The threads are
28 * synchronized so they do not attempt to use the same texture at the same time.
33 #include "piglit-util-gl.h"
34 #include "piglit-glx-util.h"
37 int piglit_width
= 50, piglit_height
= 50;
38 static int tex_width
= 512, tex_height
= 512;
39 static unsigned num_test
= 300;
40 static bool quit
= false;
43 static Window draw_win
;
44 static GLXPixmap load_win
;
45 static pthread_mutex_t mutex
;
46 static XVisualInfo
*visinfo
;
47 static GLXContext draw_ctx
, load_ctx
;
52 * user == DRAW means draw thread may draw with this texture
53 * user == LOAD means load thread may load data into this texture
54 * user == NONE means texture not in use and may be claimed by either thread
56 * Minimum of three items needed in this array for the code to work.
58 static struct texture
{
61 enum user
{ DRAW
, LOAD
, NONE
} user
;
65 * If texture at *pos is not in use claim it for 'user' and increment *pos.
66 * Return texture at *pos.
68 static struct texture
*
69 advance(int *pos
, enum user user
)
71 int cur
= *pos
% ARRAY_SIZE(texture
);
72 int next
= (cur
+ 1) % ARRAY_SIZE(texture
);
74 pthread_mutex_lock(&mutex
);
75 assert(texture
[cur
].user
== user
);
76 if (texture
[next
].user
== NONE
) {
77 texture
[cur
].user
= NONE
;
80 texture
[cur
].user
= user
;
82 pthread_mutex_unlock(&mutex
);
84 /* helps avoid starvation */
91 * Texture writing thread: loads data into successive textures, taking note
92 * of what color was used so it can be checked later.
93 * Return NULL on failure, else non-NULL.
99 struct texture
*tex
= texture
+ count
;
100 unsigned int tex_bytes
= tex_width
* tex_height
* 4;
101 unsigned char *tex_data
= malloc(tex_bytes
);
104 ret
= glXMakeCurrent(dpy
, load_win
, load_ctx
);
107 glEnable(GL_TEXTURE_2D
);
109 while (!quit
&& count
<= num_test
) {
110 int color
= (3 * count
) & 0xff;
112 assert(tex
->user
== LOAD
);
113 if (tex
->color
!= color
) {
114 memset(tex_data
, color
, tex_bytes
);
116 glBindTexture(GL_TEXTURE_2D
, tex
->id
);
117 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, tex_width
,
118 tex_height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
,
123 tex
= advance(&count
, LOAD
);
129 if (count
<= num_test
) {
138 * Texture using thread: draws with successive textures and checks that the
139 * correct color is drawn. Return NULL on failure, else non-NULL.
147 ret
= glXMakeCurrent(dpy
, draw_win
, draw_ctx
);
150 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
152 glEnable(GL_TEXTURE_2D
);
153 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
155 while (!quit
&& count
< num_test
) {
156 struct texture
*tex
= advance(&count
, DRAW
);
163 assert(tex
->user
== DRAW
);
165 glBindTexture(GL_TEXTURE_2D
, tex
->id
);
166 piglit_draw_rect_tex(0, 0, piglit_width
, piglit_height
,
169 /* first texture not filled so don't check it */
171 !piglit_probe_rect_rgb(0, 0, piglit_width
,
172 piglit_height
, expect
)) {
177 glXSwapBuffers(dpy
, draw_win
);
179 if (count
< num_test
) {
190 pthread_t draw_thread
, load_thread
;
191 void *draw_ret
, *load_ret
;
195 my_ctx
= piglit_get_glx_context_share(dpy
, visinfo
, NULL
);
196 draw_ctx
= piglit_get_glx_context_share(dpy
, visinfo
, my_ctx
);
197 load_ctx
= piglit_get_glx_context_share(dpy
, visinfo
, my_ctx
);
199 ret
= glXMakeCurrent(dpy
, draw_win
, my_ctx
);
201 piglit_dispatch_default_init(PIGLIT_DISPATCH_GL
);
203 glEnable(GL_TEXTURE_2D
);
205 for (i
= 0; i
< ARRAY_SIZE(texture
); ++i
) {
206 glGenTextures(1, &texture
[i
].id
);
207 texture
[i
].color
= -1;
208 texture
[i
].user
= NONE
;
209 glBindTexture(GL_TEXTURE_2D
, texture
[i
].id
);
210 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
212 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
214 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, tex_width
, tex_height
,
215 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
217 texture
[0].user
= DRAW
;
218 texture
[1].user
= LOAD
;
220 pthread_mutex_init(&mutex
, NULL
);
222 pthread_create(&draw_thread
, NULL
, draw_func
, NULL
);
223 pthread_create(&load_thread
, NULL
, load_func
, NULL
);
225 ret
= pthread_join(draw_thread
, &draw_ret
);
227 ret
= pthread_join(load_thread
, &load_ret
);
230 pthread_mutex_destroy(&mutex
);
232 glXDestroyContext(dpy
, load_ctx
);
233 glXDestroyContext(dpy
, draw_ctx
);
234 glXDestroyContext(dpy
, my_ctx
);
236 return draw_ret
&& load_ret
? PIGLIT_PASS
: PIGLIT_FAIL
;
240 main(int argc
, char **argv
)
245 for(i
= 1; i
< argc
; ++i
) {
246 if (!strcmp(argv
[i
], "-auto"))
247 piglit_automatic
= 1;
249 fprintf(stderr
, "Unknown option: %s\n", argv
[i
]);
253 dpy
= XOpenDisplay(NULL
);
255 fprintf(stderr
, "couldn't open display\n");
256 piglit_report_result(PIGLIT_FAIL
);
258 visinfo
= piglit_get_glx_visual(dpy
);
259 draw_win
= piglit_get_glx_window(dpy
, visinfo
);
260 pixmap
= XCreatePixmap(dpy
, DefaultRootWindow(dpy
),
261 piglit_width
, piglit_height
, visinfo
->depth
);
262 load_win
= glXCreateGLXPixmap(dpy
, visinfo
, pixmap
);
264 piglit_glx_event_loop(dpy
, draw
);