1 /*
2  * Copyright © 2009 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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #if defined(__FreeBSD__) || defined(__DragonFly__)
31 #include <libgen.h> /* for basename() */
32 #endif
33 
34 #include "piglit-util-gl.h"
35 #include "piglit-framework-gl/piglit_gl_framework.h"
36 
37 struct piglit_gl_framework *gl_fw;
38 
39 const char *piglit_binary_name;
40 bool piglit_dump_png = false;
41 bool piglit_use_fbo = false;
42 bool piglit_khr_no_error = false;
43 int piglit_automatic = 0;
44 unsigned piglit_winsys_fbo = 0;
45 
46 int piglit_width;
47 int piglit_height;
48 
49 static void
50 process_args(int *argc, char *argv[], unsigned *force_samples,
51 	     struct piglit_gl_test_config *config);
52 
53 bool
piglit_gl_test_config_override_size(struct piglit_gl_test_config * config)54 piglit_gl_test_config_override_size(struct piglit_gl_test_config *config)
55 {
56 	const char *default_size;
57 	unsigned int width;
58 	unsigned int height;
59 
60 	default_size = getenv("PIGLIT_DEFAULT_SIZE");
61 	if (!default_size)
62 		return false;
63 
64 	if (sscanf(default_size, "%ux%u", &width, &height) != 2)
65 		return false;
66 
67 	if (width == 0 || height == 0)
68 		return false;
69 
70 	config->window_width = width;
71 	config->window_height = height;
72 	return true;
73 }
74 
75 void
piglit_gl_test_config_init(struct piglit_gl_test_config * config)76 piglit_gl_test_config_init(struct piglit_gl_test_config *config)
77 {
78 	memset(config, 0, sizeof(*config));
79 
80 	if (!piglit_gl_test_config_override_size(config)) {
81 		/* Default window size.  Note: Win8's min window width */
82 		/* seems to be 160 pixels.  When the window size is */
83 		/* unexpectedly resized, tests are marked as "WARN". */
84 		/* Let's use a larger default to avoid that. */
85 		config->window_width = 160;
86 		config->window_height = 160;
87 	}
88 
89 	config->khr_no_error_support = PIGLIT_UNKNOWN_ERROR_STATUS;
90 }
91 
92 static void
delete_arg(char * argv[],int * argc,int arg)93 delete_arg(char *argv[], int *argc, int arg)
94 {
95 	int i;
96 
97 	for (i = arg + 1; i < *argc; i++) {
98 		argv[i - 1] = argv[i];
99 	}
100 	(*argc)--;
101 }
102 
103 /**
104  * Recognized arguments are removed from @a argv. The updated array
105  * length is returned in @a argc.
106  */
107 static void
process_args(int * argc,char * argv[],unsigned * force_samples,struct piglit_gl_test_config * config)108 process_args(int *argc, char *argv[], unsigned *force_samples,
109 	     struct piglit_gl_test_config *config)
110 {
111 	int j;
112 
113 	piglit_binary_name = argv[0];
114 
115 	piglit_parse_subtest_args(argc, argv, config->subtests,
116 				  &config->selected_subtests,
117 				  &config->num_selected_subtests);
118 
119 	/* Find/remove "-auto" and "-fbo" from the argument vector.
120 	 */
121 	for (j = 1; j < *argc; j++) {
122 		if (!strcmp(argv[j], "-auto")) {
123 			piglit_automatic = 1;
124 			delete_arg(argv, argc, j--);
125 		} else if (!strcmp(argv[j], "-fbo")) {
126 			piglit_use_fbo = true;
127 			delete_arg(argv, argc, j--);
128 		} else if (!strcmp(argv[j], "-png")) {
129 			piglit_dump_png = true;
130 			delete_arg(argv, argc, j--);
131 		} else if (!strcmp(argv[j], "-rlimit")) {
132 			char *ptr;
133 			unsigned long lim;
134 			int i;
135 
136 			j++;
137 			if (j >= *argc) {
138 				fprintf(stderr,
139 					"-rlimit requires an argument\n");
140 				piglit_report_result(PIGLIT_FAIL);
141 			}
142 
143 			lim = strtoul(argv[j], &ptr, 0);
144 			if (ptr == argv[j]) {
145 				fprintf(stderr,
146 					"-rlimit requires an argument\n");
147 				piglit_report_result(PIGLIT_FAIL);
148 			}
149 
150 			piglit_set_rlimit(lim);
151 
152 			/* Remove 2 arguments (hence the 'i - 2') from the
153 			 * command line.
154 			 */
155 			for (i = j + 1; i < *argc; i++) {
156 				argv[i - 2] = argv[i];
157 			}
158 			*argc -= 2;
159 			j -= 2;
160 		} else if (!strncmp(argv[j], "-samples=", 9)) {
161 			*force_samples = atoi(argv[j]+9);
162 			delete_arg(argv, argc, j--);
163 		} else if (!strcmp(argv[j], "-khr_no_error")) {
164 			piglit_khr_no_error = true;
165 			delete_arg(argv, argc, j--);
166 			if (config->khr_no_error_support ==
167 			    PIGLIT_UNKNOWN_ERROR_STATUS) {
168 				fprintf(stderr,
169 					"khr_no_error_support unknown "
170 					"skipping test!\n");
171 				piglit_report_result(PIGLIT_SKIP);
172 			} else if (config->khr_no_error_support ==
173 				   PIGLIT_HAS_ERRORS) {
174 				piglit_report_result(PIGLIT_SKIP);
175 			} else {
176 				assert(config->khr_no_error_support ==
177 				       PIGLIT_NO_ERRORS);
178 			}
179 		} else if (!strcmp(argv[j], "-compat")) {
180 			if (config->supports_gl_es_version) {
181 				fprintf(stderr,
182 					"-compat isn't allowed with ES tests!\n");
183 				piglit_report_result(PIGLIT_FAIL);
184 			}
185 			config->supports_gl_compat_version = 10;
186 			config->supports_gl_core_version = 0;
187 			puts("The compatibility profile forced.");
188 			delete_arg(argv, argc, j--);
189 		}
190 	}
191 }
192 
193 void
piglit_gl_process_args(int * argc,char * argv[],struct piglit_gl_test_config * config)194 piglit_gl_process_args(int *argc, char *argv[],
195 		       struct piglit_gl_test_config *config)
196 {
197 	unsigned force_samples = 0;
198 
199 	process_args(argc, argv, &force_samples, config);
200 
201 	if (force_samples > 1)
202 		config->window_samples = force_samples;
203 
204 }
205 
206 static void
destroy(void)207 destroy(void)
208 {
209 	if (!gl_fw)
210 		return;
211 
212 	if (gl_fw->destroy)
213 		gl_fw->destroy(gl_fw);
214 	gl_fw = NULL;
215 }
216 
217 void
piglit_gl_test_run(int argc,char * argv[],const struct piglit_gl_test_config * config)218 piglit_gl_test_run(int argc, char *argv[],
219 		   const struct piglit_gl_test_config *config)
220 {
221 	piglit_width = config->window_width;
222 	piglit_height = config->window_height;
223 
224 	gl_fw = piglit_gl_framework_factory(config);
225 	if (gl_fw == NULL) {
226 		printf("piglit: error: failed to create "
227 		       "piglit_gl_framework\n");
228 		piglit_report_result(PIGLIT_FAIL);
229 	}
230 
231 	atexit(destroy);
232 	gl_fw->run_test(gl_fw, argc, argv);
233 	assert(false);
234 }
235 
236 void
piglit_post_redisplay(void)237 piglit_post_redisplay(void)
238 {
239 	if (gl_fw->post_redisplay)
240 		gl_fw->post_redisplay(gl_fw);
241 }
242 
243 void
piglit_set_keyboard_func(void (* func)(unsigned char key,int x,int y))244 piglit_set_keyboard_func(void (*func)(unsigned char key, int x, int y))
245 {
246 	if (gl_fw->set_keyboard_func)
247 		gl_fw->set_keyboard_func(gl_fw, func);
248 }
249 
250 void
piglit_swap_buffers(void)251 piglit_swap_buffers(void)
252 {
253 	if (gl_fw->swap_buffers)
254 		gl_fw->swap_buffers(gl_fw);
255 }
256 
257 void
piglit_present_results(void)258 piglit_present_results(void)
259 {
260 	if (piglit_dump_png) {
261 		static char *fileprefix = NULL;
262 		static int frame = 0;
263 		char *filename;
264 		GLenum base_format = GL_RGBA;
265 		GLubyte *image;
266 		if (fileprefix == NULL) {
267 			int i;
268 			fileprefix = strdup(piglit_binary_name);
269 			fileprefix = basename(fileprefix);
270 			/* Strip potentially bad characters */
271 			for (i = 0; fileprefix[i]; i++) {
272 				if (!isalnum(fileprefix[i]) && fileprefix[i] != '-')
273 					fileprefix[i] = '_';
274 			}
275 		}
276 		image = malloc(4 * piglit_width * piglit_height);
277 		glReadPixels(0, 0, piglit_width, piglit_height,
278 			     base_format, GL_UNSIGNED_BYTE, image);
279 		assert(glGetError() == GL_NO_ERROR);
280 
281 		(void)!asprintf(&filename, "%s%03d.png", fileprefix, frame++);
282 
283 		printf("Writing %s...\n", filename);
284 		piglit_write_png(filename, base_format, piglit_width,
285 				 piglit_height, image, true);
286 		free(filename);
287 		free(image);
288 	}
289 
290 	if (!piglit_automatic)
291 		piglit_swap_buffers();
292 }
293 
294 void
piglit_set_reshape_func(void (* func)(int w,int h))295 piglit_set_reshape_func(void (*func)(int w, int h))
296 {
297 	if (!gl_fw->set_reshape_func)
298 		gl_fw->set_reshape_func(gl_fw, func);
299 }
300 
301 enum piglit_result
piglit_create_dma_buf(unsigned w,unsigned h,unsigned fourcc,const void * src_data,struct piglit_dma_buf ** buf)302 piglit_create_dma_buf(unsigned w, unsigned h, unsigned fourcc,
303 		      const void *src_data, struct piglit_dma_buf **buf)
304 {
305 	if (!gl_fw->create_dma_buf)
306 		return PIGLIT_SKIP;
307 
308 	return gl_fw->create_dma_buf(w, h, fourcc, src_data, buf);
309 }
310 
311 void
piglit_destroy_dma_buf(struct piglit_dma_buf * buf)312 piglit_destroy_dma_buf(struct piglit_dma_buf *buf)
313 {
314 	if (gl_fw->destroy_dma_buf)
315 		gl_fw->destroy_dma_buf(buf);
316 }
317 
318 size_t
piglit_get_selected_tests(const char *** selected_subtests)319 piglit_get_selected_tests(const char ***selected_subtests)
320 {
321 	*selected_subtests = gl_fw->test_config->selected_subtests;
322 	return gl_fw->test_config->num_selected_subtests;
323 }
324