1 /*
2  * Copyright © 2011 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * @file glx-query-drawable.c
26  *
27  * Test the behavior of glXQueryDrawable(). See GLX 1.4 spec, Section 3.3.6
28  * Querying Attributes.
29  *
30  * For usage information, see usage_error();
31  */
32 
33 #include "piglit-util-gl.h"
34 #include "piglit-glx-util.h"
35 
36 int piglit_width = 137;
37 int piglit_height = 119;
38 GLXFBConfig config = None;
39 
40 enum _drawable_type {
41     WINDOW,
42     GLXWINDOW,
43     GLXPIXMAP,
44     GLXPBUFFER,
45 };
46 
47 int drawable_type /* = WINDOW */;
48 
49 void
usage_error()50 usage_error()
51 {
52    const char *message =
53 	"usage:\n"
54 	"    glx-query-drawable --bad-drawable\n"
55 	"        Call glXQueryDrawable(drawable=0) and expect that error\n"
56 	"        GLXBadDrawable is generated.\n"
57 	"\n"
58 	"    glx-query-drawable --attr=GLX_WIDTH\n"
59 	"    glx-query-drawable --attr=GLX_HEIGHT\n"
60 	"    glx-query-drawable --attr=GLX_FBCONFIG_ID\n"
61 	"    glx-query-drawable --attr=GLX_PRESERVED_CONTENTS (pbuffer only)\n"
62 	"        Call glXQueryDrawable() with the given attribute.\n"
63 	"\n"
64 	"    Options:\n"
65 	"        -auto"
66 	"        --type={GLX{WINDOW,PIXMAP,PBUFFER},WINDOW}\n"
67 	"    Default is: not -auto, WINDOW\n";
68 	printf("%s", message);
69 	piglit_report_result(PIGLIT_FAIL);
70 }
71 
72 /***************************************************************************/
73 
74 /**
75  * @name X Error Handlers
76  * @{
77  */
78 
79 bool found_error_glxbaddrawable = false;
80 
81 static int
expect_no_error(Display * display,XErrorEvent * error)82 expect_no_error(Display *display, XErrorEvent *error)
83 {
84 	static char buf[256];
85 	XGetErrorText(display, error->error_code, buf, 256);
86 	fprintf(stderr, "error: unexpected X error: %s\n", buf);
87 	piglit_report_result(PIGLIT_FAIL);
88 	return 0;
89 }
90 
91 static int
expect_glxbaddrawable(Display * display,XErrorEvent * error)92 expect_glxbaddrawable(Display *display, XErrorEvent *error)
93 {
94 	if (piglit_glx_get_error(display, error) == GLXBadDrawable) {
95 		found_error_glxbaddrawable = true;
96 	} else {
97 		static char buf[256];
98 		XGetErrorText(display, error->error_code, buf, 256);
99 		fprintf(stderr, "error: unexpected X error: %s\n", buf);
100 		piglit_report_result(PIGLIT_FAIL);
101 	}
102 	return 0;
103 }
104 
105 /***************************************************************************/
106 
107 /**
108  * @}
109  * @name Test Functions
110  * @{
111  */
112 
query_width(Display * display,GLXDrawable draw)113 static void query_width(Display *display, GLXDrawable draw) {
114 	unsigned int width = 0;
115 
116 	XSetErrorHandler(expect_no_error);
117 	glXQueryDrawable(display, draw, GLX_WIDTH, &width);
118 
119 	/* Sync before checking width in order to catch X errors. */
120 	XSync(display, 0);
121 
122 	if (width != piglit_width) {
123 		fprintf(stderr,
124 		        "error: width=%d but glXQueryDrawable returned %d\n",
125 		        piglit_width, width);
126 		piglit_report_result(PIGLIT_FAIL);
127 	}
128 
129 	piglit_report_result(PIGLIT_PASS);
130 }
131 
query_height(Display * display,GLXDrawable draw)132 static void query_height(Display *display, GLXDrawable draw) {
133 	unsigned int height = 0;
134 
135 	XSetErrorHandler(expect_no_error);
136 	glXQueryDrawable(display, draw, GLX_HEIGHT, &height);
137 
138 	/* Sync before checking height in order to catch X errors. */
139 	XSync(display, 0);
140 
141 	if (height != piglit_height) {
142 		fprintf(stderr,
143 		        "error: height=%d but glXQueryDrawable returned %d\n",
144 		        piglit_height, height);
145 		piglit_report_result(PIGLIT_FAIL);
146 	}
147 
148 	piglit_report_result(PIGLIT_PASS);
149 }
150 
query_fbconfig_id(Display * display,GLXDrawable draw)151 static void query_fbconfig_id(Display *display, GLXDrawable draw) {
152 	unsigned int id = 0;
153 	int piglit_id = 0;
154 	enum piglit_result result = PIGLIT_PASS;
155 
156 	XSetErrorHandler(expect_no_error);
157 	glXQueryDrawable(display, draw, GLX_FBCONFIG_ID, &id);
158 	glXGetFBConfigAttrib(display, config, GLX_FBCONFIG_ID, &piglit_id);
159 
160 	/* Sync before checking in order to catch X errors. */
161 	XSync(display, 0);
162 
163 	if (id == 0) {
164 		fprintf(stderr, "error: no fbconfig id returned\n");
165 		result = PIGLIT_FAIL;
166 	}
167 
168 	if (id != piglit_id) {
169 		if (!(drawable_type == WINDOW && id == None)) {
170 			fprintf(stderr, "error: id=%d but should be %d\n",
171 				id, piglit_id);
172 			result = PIGLIT_FAIL;
173 		}
174 	}
175 
176 	piglit_report_result(result);
177 }
178 
query_preserved_contents(Display * display,GLXDrawable draw)179 static void query_preserved_contents(Display *display, GLXDrawable draw) {
180 	unsigned int contents = 42;
181 	enum piglit_result result = PIGLIT_PASS;
182 
183 	if ((contents == True) || (contents == False)) {
184 		fprintf(stderr, "This is a very strange dojo\n");
185 		piglit_report_result(PIGLIT_SKIP);
186 		return;
187 	}
188 
189 	XSetErrorHandler(expect_no_error);
190 	glXQueryDrawable(display, draw, GLX_PRESERVED_CONTENTS, &contents);
191 
192 	/* Sync before checking in order to catch X errors. */
193 	XSync(display, 0);
194 
195 	if ((contents != True) && (contents != False)) {
196 		fprintf(stderr, "error: Unexpected value %d\n", contents);
197 		result = PIGLIT_FAIL;
198 	}
199 
200 	piglit_report_result(result);
201 }
202 
query_bad_drawable(Display * display,GLXDrawable draw)203 static void query_bad_drawable(Display *display, GLXDrawable draw) {
204 	unsigned int width;
205 	(void) draw;
206 
207 	XSetErrorHandler(expect_glxbaddrawable);
208 	glXQueryDrawable(display, 0, GLX_WIDTH, &width);
209 	XSync(display, 0);
210 
211 	if (!found_error_glxbaddrawable) {
212 		fprintf(stderr,
213 		        "error: glXQueryDrawable(draw=0) did not generate "
214 		        "GLXBadDrawable\n");
215 		piglit_report_result(PIGLIT_FAIL);
216 	}
217 
218 	piglit_report_result(PIGLIT_PASS);
219 }
220 
221 /** @} */
222 
223 /***************************************************************************/
224 
225 static void
parse_args(int argc,char ** argv,void (** test_func)(Display *,GLXDrawable))226 parse_args(int argc, char **argv,
227            void (**test_func)(Display*, GLXDrawable))
228 {
229 	int i;
230 
231 	/* Count of parsed args, excluding -auto. */
232 	int num_parsed_args = 0;
233 
234 	for (i = 1; i < argc; ++i) {
235 		const char *arg = argv[i];
236 		if (!strncmp(arg, "-auto", 5)) {
237 			piglit_automatic = 1;
238 		} else if (!strncmp(arg, "--bad-drawable", 14)) {
239 			++num_parsed_args;
240 			*test_func = query_bad_drawable;
241 		} else if (!strncmp(arg, "--attr=GLX_WIDTH", 16)) {
242 			++num_parsed_args;
243 			*test_func = query_width;
244 		} else if (!strncmp(arg, "--attr=GLX_HEIGHT", 17)) {
245 			++num_parsed_args;
246 			*test_func = query_height;
247 		} else if (!strncmp(arg, "--attr=GLX_FBCONFIG_ID", 22)) {
248 			++num_parsed_args;
249 			*test_func = query_fbconfig_id;
250 		} else if (!strncmp(arg, "--attr=GLX_PRESERVED_CONTENTS", 29)) {
251 			++num_parsed_args;
252 			*test_func = query_preserved_contents;
253 		} else if (!strncmp(arg, "--type=GLXWINDOW", 16)) {
254 			++num_parsed_args;
255 			drawable_type = GLXWINDOW;
256 		} else if (!strncmp(arg, "--type=GLXPIXMAP", 16)) {
257 			++num_parsed_args;
258 			drawable_type = GLXPIXMAP;
259 		} else if (!strncmp(arg, "--type=GLXPBUFFER", 17)) {
260 			++num_parsed_args;
261 			drawable_type = GLXPBUFFER;
262 		} else if (!strncmp(arg, "--type=WINDOW", 13)) {
263 			++num_parsed_args;
264 			drawable_type = WINDOW;
265 		} else {
266 		   /* Unrecognized argument. */
267 		   usage_error();
268 		}
269 	}
270 
271 	if (*test_func == query_preserved_contents)
272 	    if (drawable_type != GLXPBUFFER)
273 		usage_error();
274 
275 	if (num_parsed_args < 1) {
276 	   usage_error();
277 	}
278 }
279 
main(int argc,char ** argv)280 int main(int argc, char **argv) {
281 	Display *display;
282 	XVisualInfo *visual;
283 	GLXDrawable draw;
284 	GLXContext ctx;
285 	void (*test_func)(Display*, GLXDrawable);
286 
287 	parse_args(argc, argv, &test_func);
288 
289 	display = piglit_get_glx_display();
290 	piglit_require_glx_version(display, 1, 3);
291 
292 	visual = piglit_get_glx_visual(display);
293 	config = piglit_glx_get_fbconfig_for_visinfo(display, visual);
294 	ctx = piglit_get_glx_context(display, visual);
295 
296 	switch (drawable_type) {
297 	case GLXWINDOW:
298 	    draw = glXCreateWindow(display, config,
299 				   piglit_get_glx_window(display, visual),
300 				   NULL);
301 	    break;
302 	case GLXPIXMAP:
303 	    draw = glXCreatePixmap(display, config,
304 				   XCreatePixmap(display,
305 						 DefaultRootWindow(display),
306 						 piglit_width, piglit_height,
307 						 visual->depth),
308 				   NULL);
309 	    break;
310 	case GLXPBUFFER: {
311 	    int attribs[] = { GLX_PBUFFER_WIDTH, piglit_width,
312 			      GLX_PBUFFER_HEIGHT, piglit_height,
313 			      None };
314 	    draw = glXCreatePbuffer(display, config, attribs);
315 	    break;
316 	    }
317 	case WINDOW:
318 	    draw = piglit_get_glx_window(display, visual);
319 	    break;
320 	default:
321 	    assert(0);
322 	    draw = 0;
323 	}
324 
325 	glXMakeCurrent(display, draw, ctx);
326 
327 	/* Must initialize static variables of this function. */
328 	piglit_glx_get_error(display, NULL);
329 
330 	test_func(display, draw);
331 
332 	return 0;
333 }
334