shader_runner.c 25.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#define _GNU_SOURCE
25 26 27 28 29
#if defined(_MSC_VER)
#define bool BOOL
#define true 1
#define false 0
#else
30
#include <stdbool.h>
31
#endif
32 33
#include <string.h>
#include <ctype.h>
Jose Fonseca's avatar
Jose Fonseca committed
34
#if defined(_WIN32)
35 36
#include <stdlib.h>
#else
37
#include <libgen.h>
38
#endif
39 40 41
#include "piglit-util.h"

int piglit_width = 250, piglit_height = 250;
42
int piglit_window_mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE;
43 44 45

static float gl_version = 0.0;
static float glsl_version = 0.0;
46 47
static int gl_max_fragment_uniform_components;
static int gl_max_vertex_uniform_components;
48

49
const char *path = NULL;
50 51 52 53 54 55 56 57 58
const char *test_start = NULL;

GLuint vertex_shaders[256];
unsigned num_vertex_shaders = 0;
GLuint geometry_shaders[256];
unsigned num_geometry_shaders = 0;
GLuint fragment_shaders[256];
unsigned num_fragment_shaders = 0;

59 60 61 62 63 64 65 66 67
/**
 * List of strings loaded from files
 *
 * Some test script sections, such as "[vertex shader file]", can supply shader
 * source code from multiple disk files.  This array stores those strings.
 */
char *shader_strings[256];
GLsizei shader_string_sizes[256];
unsigned num_shader_strings = 0;
68
GLuint prog;
69

70 71 72 73
enum states {
	none = 0,
	requirements,
	vertex_shader,
74
	vertex_shader_file,
75 76
	vertex_program,
	geometry_shader,
77
	geometry_shader_file,
78 79
	geometry_program,
	fragment_shader,
80
	fragment_shader_file,
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
	fragment_program,
	test,
};


enum comparison {
	equal = 0,
	not_equal,
	less,
	greater_equal,
	greater,
	less_equal
};


96 97 98
void
compile_glsl(GLenum target, bool release_text)
{
99
	GLuint shader = piglit_CreateShader(target);
100 101 102
	GLint ok;
	unsigned i;

103 104 105 106 107 108 109 110 111 112 113 114
	switch (target) {
	case GL_VERTEX_SHADER:
		piglit_require_vertex_shader();
		break;
	case GL_FRAGMENT_SHADER:
		piglit_require_fragment_shader();
		break;
	case GL_GEOMETRY_SHADER_ARB:
		if (gl_version < 3.2)
			piglit_require_extension("GL_ARB_geometry_shader4");
		break;
	}
115

116 117 118
	piglit_ShaderSource(shader, num_shader_strings,
			    (const GLchar **) shader_strings,
			    shader_string_sizes);
119

120 121 122
	piglit_CompileShader(shader);

	piglit_GetShaderiv(shader, GL_COMPILE_STATUS, &ok);
123 124 125 126 127

	if (!ok) {
		GLchar *info;
		GLint size;

128
		piglit_GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
129 130
		info = malloc(size);

131
		piglit_GetShaderInfoLog(shader, size, NULL, info);
132 133 134 135 136 137

		fprintf(stderr, "Failed to compile %s: %s\n",
			target == GL_FRAGMENT_SHADER ? "FS" : "VS",
			info);

		free(info);
138
		piglit_report_result(PIGLIT_FAIL);
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	}

	if (release_text) {
		for (i = 0; i < num_shader_strings; i++)
			free(shader_strings[i]);
	}

	switch (target) {
	case GL_VERTEX_SHADER:
		vertex_shaders[num_vertex_shaders] = shader;
		num_vertex_shaders++;
		break;
	case GL_GEOMETRY_SHADER_ARB:
		geometry_shaders[num_geometry_shaders] = shader;
		num_geometry_shaders++;
		break;
	case GL_FRAGMENT_SHADER:
		fragment_shaders[num_fragment_shaders] = shader;
		num_fragment_shaders++;
		break;
	}
}


163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
/**
 * Copy a string until either whitespace or the end of the string
 */
const char *
strcpy_to_space(char *dst, const char *src)
{
	while (!isspace(*src) && (*src != '\0'))
		*(dst++) = *(src++);

	*dst = '\0';
	return src;
}


/**
 * Skip over whitespace upto the end of line
 */
const char *
eat_whitespace(const char *src)
{
	while (isspace(*src) && (*src != '\n'))
		src++;

	return src;
}


190 191 192 193 194 195 196 197 198 199 200 201 202
/**
 * Skip over non-whitespace upto the end of line
 */
const char *
eat_text(const char *src)
{
	while (!isspace(*src) && (*src != '\0'))
		src++;

	return src;
}


203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
/**
 * Compare two values given a specified comparison operator
 */
bool
compare(float ref, float value, enum comparison cmp)
{
	switch (cmp) {
	case equal:         return value == ref;
	case not_equal:     return value != ref;
	case less:          return value <  ref;
	case greater_equal: return value >= ref;
	case greater:       return value >  ref;
	case less_equal:    return value <= ref;
	}

	assert(!"Should not get here.");
}


/**
 * Get the string representation of a comparison operator
 */
const char *
comparison_string(enum comparison cmp)
{
	switch (cmp) {
	case equal:         return "==";
	case not_equal:     return "!=";
	case less:          return "<";
	case greater_equal: return ">=";
	case greater:       return ">";
	case less_equal:    return "<=";
	}

	assert(!"Should not get here.");
}


241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
void
load_shader_file(const char *line)
{
	GLsizei *const size = &shader_string_sizes[num_shader_strings];
	char buf[256];
	char *text;

	strcpy_to_space(buf, line);

	text = piglit_load_text_file(buf, (unsigned *) size);
	if ((text == NULL) && (path != NULL)) {
		const size_t len = strlen(path);

		memcpy(buf, path, len);
		buf[len] = '/';
		strcpy_to_space(&buf[len + 1], line);

		text = piglit_load_text_file(buf, (unsigned *) size);
	}

	if (text == NULL) {
		strcpy_to_space(buf, line);

		printf("could not load file \"%s\"\n", buf);
265
		piglit_report_result(PIGLIT_FAIL);
266 267 268 269 270 271 272
	}

	shader_strings[num_shader_strings] = text;
	num_shader_strings++;
}


273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
/**
 * Parse a binary comparison operator and return the matching token
 */
const char *
process_comparison(const char *src, enum comparison *cmp)
{
	char buf[32];

	switch (src[0]) {
	case '=':
		if (src[1] == '=') {
			*cmp = equal;
			return src + 2;
		}
		break;
	case '<':
		if (src[1] == '=') {
			*cmp = less_equal;
			return src + 2;
		} else {
			*cmp = less;
			return src + 1;
		}
	case '>':
		if (src[1] == '=') {
			*cmp = greater_equal;
			return src + 2;
		} else {
			*cmp = greater;
			return src + 1;
		}
	case '!':
		if (src[1] == '=') {
			*cmp = not_equal;
			return src + 2;
		}
		break;
	}

	strncpy(buf, src, sizeof(buf));
	buf[sizeof(buf) - 1] = '\0';
	printf("invalid comparison in test script:\n%s\n", buf);
315
	piglit_report_result(PIGLIT_FAIL);
316 317 318 319 320 321 322 323 324 325 326 327 328 329

	/* Won't get here. */
	return NULL;
}


/**
 * Parse and check a line from the requirement section of the test
 */
void
process_requirement(const char *line)
{
	char buffer[4096];

330
	/* There are four types of requirements that a test can currently
331 332 333 334 335
	 * have:
	 *
	 *    * Require that some GL extension be supported
	 *    * Require some particular versions of GL
	 *    * Require some particular versions of GLSL
336
	 *    * Require some particular number of uniform components
337 338 339 340 341 342
	 *
	 * The tests for GL and GLSL versions can be equal, not equal,
	 * less, less-or-equal, greater, or greater-or-equal.  Extension tests
	 * can also require that a particular extension not be supported by
	 * prepending ! to the extension name.
	 */
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
	if (strncmp("GL_MAX_FRAGMENT_UNIFORM_COMPONENTS", line, 34) == 0) {
		enum comparison cmp;
		int maxcomp;

		line = eat_whitespace(line + 34);

		line = process_comparison(line, &cmp);

		maxcomp = atoi(line);
		if (!compare(maxcomp, gl_max_fragment_uniform_components, cmp)) {
			printf("Test requires max fragment uniform components %s %i.  "
			       "The driver supports %i.\n",
			       comparison_string(cmp),
			       maxcomp,
			       gl_max_fragment_uniform_components);
			piglit_report_result(PIGLIT_SKIP);
		}
	} else if (strncmp("GL_MAX_VERTEX_UNIFORM_COMPONENTS", line, 32) == 0) {
		enum comparison cmp;
		int maxcomp;

		line = eat_whitespace(line + 32);

		line = process_comparison(line, &cmp);

		maxcomp = atoi(line);
		if (!compare(maxcomp, gl_max_vertex_uniform_components, cmp)) {
			printf("Test requires max vertex uniform components %s %i.  "
			       "The driver supports %i.\n",
			       comparison_string(cmp),
			       maxcomp,
			       gl_max_vertex_uniform_components);
			piglit_report_result(PIGLIT_SKIP);
		}
	} else if (strncmp("GL_", line, 3) == 0) {
378 379 380 381 382 383 384 385 386 387 388 389 390
		strcpy_to_space(buffer, line);
		piglit_require_extension(buffer);
	} else if (strncmp("!GL_", line, 4) == 0) {
		strcpy_to_space(buffer, line + 1);
		piglit_require_not_extension(buffer);
	} else if (strncmp("GLSL", line, 4) == 0) {
		enum comparison cmp;
		float version;

		line = eat_whitespace(line + 4);

		line = process_comparison(line, &cmp);

391
		version = strtod(line, NULL);
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
		if (!compare(version, glsl_version, cmp)) {
			printf("Test requires GLSL version %s %.1f.  "
			       "Actual version is %.1f.\n",
			       comparison_string(cmp),
			       version,
			       glsl_version);
			piglit_report_result(PIGLIT_SKIP);
		}
	} else if (strncmp("GL", line, 2) == 0) {
		enum comparison cmp;
		float version;

		line = eat_whitespace(line + 2);

		line = process_comparison(line, &cmp);

408
		version = strtod(line, NULL);
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
		if (!compare(version, gl_version, cmp)) {
			printf("Test requires GL version %s %.1f.  "
			       "Actual version is %.1f.\n",
			       comparison_string(cmp),
			       version,
			       gl_version);
			piglit_report_result(PIGLIT_SKIP);
		}
	}
}


void
leave_state(enum states state, const char *line)
{
	switch (state) {
	case none:
		break;

	case requirements:
		break;

	case vertex_shader:
432 433 434 435 436 437 438
		shader_string_sizes[0] = line - shader_strings[0];
		num_shader_strings = 1;
		compile_glsl(GL_VERTEX_SHADER, false);
		break;

	case vertex_shader_file:
		compile_glsl(GL_VERTEX_SHADER, true);
439 440 441 442 443 444 445 446 447 448 449 450
		break;

	case vertex_program:
		break;

	case geometry_shader:
		break;

	case geometry_program:
		break;

	case fragment_shader:
451 452 453 454 455 456 457
		shader_string_sizes[0] = line - shader_strings[0];
		num_shader_strings = 1;
		compile_glsl(GL_FRAGMENT_SHADER, false);
		break;

	case fragment_shader_file:
		compile_glsl(GL_FRAGMENT_SHADER, true);
458 459 460 461 462 463 464
		break;

	case fragment_program:
		break;

	case test:
		break;
465 466 467

	default:
		assert(!"Not yet supported.");
468 469 470 471 472 473 474 475 476
	}
}


void
link_and_use_shaders(void)
{
	unsigned i;
	GLenum err;
477
	GLint ok;
478 479 480 481 482 483

	if ((num_vertex_shaders == 0)
	    && (num_fragment_shaders == 0)
	    && (num_geometry_shaders == 0))
		return;

484
	prog = piglit_CreateProgram();
485 486

	for (i = 0; i < num_vertex_shaders; i++) {
487
		piglit_AttachShader(prog, vertex_shaders[i]);
488 489 490
	}

	for (i = 0; i < num_geometry_shaders; i++) {
491
		piglit_AttachShader(prog, geometry_shaders[i]);
492 493 494
	}

	for (i = 0; i < num_fragment_shaders; i++) {
495
		piglit_AttachShader(prog, fragment_shaders[i]);
496 497
	}

498
	piglit_LinkProgram(prog);
499

500
	for (i = 0; i < num_vertex_shaders; i++) {
501
		piglit_DeleteShader(vertex_shaders[i]);
502 503 504
	}

	for (i = 0; i < num_geometry_shaders; i++) {
505
		piglit_DeleteShader(geometry_shaders[i]);
506 507 508
	}

	for (i = 0; i < num_fragment_shaders; i++) {
509
		piglit_DeleteShader(fragment_shaders[i]);
510 511
	}

512
	piglit_GetProgramiv(prog, GL_LINK_STATUS, &ok);
513 514 515 516
	if (!ok) {
		GLchar *info;
		GLint size;

517
		piglit_GetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
518 519
		info = malloc(size);

520
		piglit_GetProgramInfoLog(prog, size, NULL, info);
521 522 523 524 525

		fprintf(stderr, "Failed to link:\n%s\n",
			info);

		free(info);
526
		piglit_report_result(PIGLIT_FAIL);
527 528
	}

529
	piglit_UseProgram(prog);
530 531 532

	err = glGetError();
	if (err) {
533 534 535
		GLchar *info;
		GLint size;

536
		printf("GL error after linking program: 0x%04x\n", err);
537

538
		piglit_GetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
539 540
		info = malloc(size);

541
		piglit_GetProgramInfoLog(prog, size, NULL, info);
542 543
		fprintf(stderr, "Info log: %s\n", info);

544
		piglit_report_result(PIGLIT_FAIL);
545 546 547 548 549 550 551 552 553 554 555 556 557 558
	}
}


void
process_test_script(const char *script_name)
{
	unsigned text_size;
	char *text = piglit_load_text_file(script_name, &text_size);
	enum states state = none;
	const char *line = text;

	if (line == NULL) {
		printf("could not read file \"%s\"\n", script_name);
559
		piglit_report_result(PIGLIT_FAIL);
560 561 562 563 564 565 566 567 568 569
	}

	while (line[0] != '\0') {
		if (line[0] == '[') {
			leave_state(state, line);

			if (strncmp(line, "[require]", 9) == 0) {
				state = requirements;
			} else if (strncmp(line, "[vertex shader]", 15) == 0) {
				state = vertex_shader;
570 571 572 573 574
				shader_strings[0] = NULL;
			} else if (strncmp(line, "[vertex shader file]", 20) == 0) {
				state = vertex_shader_file;
				shader_strings[0] = NULL;
				num_shader_strings = 0;
575 576
			} else if (strncmp(line, "[fragment shader]", 17) == 0) {
				state = fragment_shader;
577 578 579 580 581
				shader_strings[0] = NULL;
			} else if (strncmp(line, "[fragment shader file]", 22) == 0) {
				state = fragment_shader_file;
				shader_strings[0] = NULL;
				num_shader_strings = 0;
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
			} else if (strncmp(line, "[test]", 6) == 0) {
				test_start = strchrnul(line, '\n');
				if (test_start[0] != '\0')
					test_start++;
				return;
			}
		} else {
			switch (state) {
			case none:
				break;

			case requirements:
				process_requirement(line);
				break;

			case vertex_shader:
			case vertex_program:
			case geometry_shader:
			case geometry_program:
			case fragment_shader:
			case fragment_program:
603 604 605 606 607 608 609 610 611 612
				if (shader_strings[0] == NULL)
					shader_strings[0] = (char *) line;
				break;

			case vertex_shader_file:
			case geometry_shader_file:
			case fragment_shader_file:
				line = eat_whitespace(line);
				if ((line[0] != '\n') && (line[0] != '#'))
				    load_shader_file(line);
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
				break;

			case test:
				break;
			}
		}

		line = strchrnul(line, '\n');
		if (line[0] != '\0')
			line++;
	}

	leave_state(state, line);
}


void
get_floats(const char *line, float *f, unsigned count)
{
	unsigned i;

	for (i = 0; i < count; i++)
635
		f[i] = strtod(line, (char **) &line);
636 637 638
}


639 640 641 642 643 644 645 646 647 648
void
get_ints(const char *line, int *ints, unsigned count)
{
	unsigned i;

	for (i = 0; i < count; i++)
		ints[i] = strtol(line, (char **) &line, 0);
}


649 650 651 652 653
void
set_uniform(const char *line)
{
	char name[512];
	float f[16];
654
	int ints[16];
655 656
	GLuint prog;
	GLint loc;
657
	const char *type;
658 659 660

	glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *) &prog);

661 662 663
	type = eat_whitespace(line);
	line = eat_text(type);

664
	line = strcpy_to_space(name, eat_whitespace(line));
665
	loc = piglit_GetUniformLocation(prog, name);
666 667 668
	if (loc < 0) {
		printf("cannot get location of uniform \"%s\"\n",
		       name);
669
		piglit_report_result(PIGLIT_FAIL);
670 671
	}

672 673
	if (strncmp("float", type, 5) == 0) {
		get_floats(line, f, 1);
674
		piglit_Uniform1fv(loc, 1, f);
675
		return;
676 677
	} else if (strncmp("int", type, 3) == 0) {
		int val = atoi(line);
678
		piglit_Uniform1i(loc, val);
679
		return;
680 681 682 683
	} else if (strncmp("vec", type, 3) == 0) {
		switch (type[3]) {
		case '2':
			get_floats(line, f, 2);
684
			piglit_Uniform2fv(loc, 1, f);
685 686 687
			return;
		case '3':
			get_floats(line, f, 3);
688
			piglit_Uniform3fv(loc, 1, f);
689 690 691
			return;
		case '4':
			get_floats(line, f, 4);
692
			piglit_Uniform4fv(loc, 1, f);
693 694
			return;
		}
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
	} else if (strncmp("ivec", type, 4) == 0) {
		switch (type[4]) {
		case '2':
			get_ints(line, ints, 2);
			piglit_Uniform2iv(loc, 1, ints);
			return;
		case '3':
			get_ints(line, ints, 3);
			piglit_Uniform3iv(loc, 1, ints);
			return;
		case '4':
			get_ints(line, ints, 4);
			piglit_Uniform4iv(loc, 1, ints);
			return;
		}
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
	} else if ((strncmp("mat", type, 3) == 0)
		   && (type[3] != '\0')
		   && (type[4] == 'x')) {
		switch (type[3]) {
		case '2':
			switch (type[5]) {
			case '2':
				get_floats(line, f, 4);
				piglit_UniformMatrix2fv(loc, 1, GL_FALSE, f);
				return;
			case '3':
				get_floats(line, f, 6);
				piglit_UniformMatrix2x3fv(loc, 1, GL_FALSE, f);
				return;
			case '4':
				get_floats(line, f, 8);
				piglit_UniformMatrix2x4fv(loc, 1, GL_FALSE, f);
				return;
			}
		case '3':
			switch (type[5]) {
			case '2':
				get_floats(line, f, 6);
				piglit_UniformMatrix3x2fv(loc, 1, GL_FALSE, f);
				return;
			case '3':
				get_floats(line, f, 9);
				piglit_UniformMatrix3fv(loc, 1, GL_FALSE, f);
				return;
			case '4':
				get_floats(line, f, 12);
				piglit_UniformMatrix3x4fv(loc, 1, GL_FALSE, f);
				return;
			}
		case '4':
			switch (type[5]) {
			case '2':
				get_floats(line, f, 8);
				piglit_UniformMatrix4x2fv(loc, 1, GL_FALSE, f);
				return;
			case '3':
				get_floats(line, f, 12);
				piglit_UniformMatrix4x3fv(loc, 1, GL_FALSE, f);
				return;
			case '4':
				get_floats(line, f, 16);
				piglit_UniformMatrix4fv(loc, 1, GL_FALSE, f);
				return;
			}
		}
760
	}
761 762 763

	strcpy_to_space(name, type);
	printf("unknown uniform type \"%s\"", name);
764
	piglit_report_result(PIGLIT_FAIL);
765 766

	return;
767 768
}

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
struct enable_table {
	const char *name;
	GLenum value;
} enable_table[] = {
	{ "GL_CLIP_PLANE0", GL_CLIP_PLANE0 },
	{ "GL_CLIP_PLANE1", GL_CLIP_PLANE1 },
	{ "GL_CLIP_PLANE2", GL_CLIP_PLANE2 },
	{ "GL_CLIP_PLANE3", GL_CLIP_PLANE3 },
	{ "GL_CLIP_PLANE4", GL_CLIP_PLANE4 },
	{ "GL_CLIP_PLANE5", GL_CLIP_PLANE5 },
	{ NULL, 0 }
};

void
do_enable_disable(const char *line, bool enable_flag)
{
	char name[512];
	int i;

	strcpy_to_space(name, eat_whitespace(line));
	for (i = 0; enable_table[i].name; ++i) {
		if (0 == strcmp(name, enable_table[i].name)) {
			if (enable_flag) {
				glEnable(enable_table[i].value);
			} else {
				glDisable(enable_table[i].value);
			}
			return;
		}
	}

	printf("unknown enable/disable enum \"%s\"", name);
	piglit_report_result(PIGLIT_FAIL);
}

804 805 806 807 808
static GLboolean
string_match(const char *string, const char *line)
{
	return (strncmp(string, line, strlen(string)) == 0);
}
809

810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
static void
draw_instanced_rect(int primcount, float x, float y, float w, float h)
{
	float verts[4][4];

	piglit_require_extension("GL_ARB_draw_instanced");

	verts[0][0] = x;
	verts[0][1] = y;
	verts[0][2] = 0.0;
	verts[0][3] = 1.0;
	verts[1][0] = x + w;
	verts[1][1] = y;
	verts[1][2] = 0.0;
	verts[1][3] = 1.0;
	verts[2][0] = x + w;
	verts[2][1] = y + h;
	verts[2][2] = 0.0;
	verts[2][3] = 1.0;
	verts[3][0] = x;
	verts[3][1] = y + h;
	verts[3][2] = 0.0;
	verts[3][3] = 1.0;

	glVertexPointer(4, GL_FLOAT, 0, verts);
	glEnableClientState(GL_VERTEX_ARRAY);

	glDrawArraysInstancedARB(GL_QUADS, 0, 4, primcount);

	glDisableClientState(GL_VERTEX_ARRAY);
}

842 843 844 845 846 847 848 849
enum piglit_result
piglit_display(void)
{
	const char *line;
	bool pass = true;
	GLbitfield clear_bits = 0;

	if (test_start == NULL)
850
		return PIGLIT_PASS;
851 852 853 854 855


	line = test_start;
	while (line[0] != '\0') {
		float c[32];
856
		double d[4];
857
		int x, y, w, h, tex, level;
858 859 860

		line = eat_whitespace(line);

861
		if (string_match("clear color", line)) {
862 863 864
			get_floats(line + 11, c, 4);
			glClearColor(c[0], c[1], c[2], c[3]);
			clear_bits |= GL_COLOR_BUFFER_BIT;
865
		} else if (string_match("clear", line)) {
866
			glClear(clear_bits);
867 868 869 870 871 872 873 874
		} else if (sscanf(line,
				  "clip plane %d %lf %lf %lf %lf",
				  &x, &d[0], &d[1], &d[2], &d[3])) {
			if (x < 0 || x >= GL_MAX_CLIP_PLANES) {
				printf("clip plane id %d out of range", x);
				piglit_report_result(PIGLIT_FAIL);
			}
			glClipPlane(GL_CLIP_PLANE0 + x, d);
875
		} else if (string_match("draw rect", line)) {
876 877
			get_floats(line + 9, c, 4);
			piglit_draw_rect(c[0], c[1], c[2], c[3]);
878 879 880 881 882 883 884
		} else if (string_match("draw instanced rect", line)) {
			int primcount;

			sscanf(line + 19, "%d %f %f %f %f",
			       &primcount,
			       c + 0, c + 1, c + 2, c + 3);
			draw_instanced_rect(primcount, c[0], c[1], c[2], c[3]);
885 886 887 888
		} else if (string_match("disable", line)) {
			do_enable_disable(line + 7, false);
		} else if (string_match("enable", line)) {
			do_enable_disable(line + 6, true);
889 890 891 892
		} else if (sscanf(line, "ortho %f %f %f %f",
				  c + 0, c + 1, c + 2, c + 3) == 4) {
			piglit_gen_ortho_projection(c[0], c[1], c[2], c[3],
						    -1, 1, GL_FALSE);
893
		} else if (string_match("ortho", line)) {
894 895
			piglit_ortho_projection(piglit_width, piglit_height,
						GL_FALSE);
896
		} else if (string_match("probe rgba", line)) {
897
			get_floats(line + 10, c, 6);
898
			if (!piglit_probe_pixel_rgba((int) c[0], (int) c[1],
899 900 901
						    & c[2])) {
				pass = false;
			}
902 903 904 905 906
		} else if (sscanf(line,
				  "relative probe rgba ( %f , %f ) "
				  "( %f , %f , %f , %f )",
				  c + 0, c + 1,
				  c + 2, c + 3, c + 4, c + 5) == 6) {
907 908 909 910 911 912 913 914
			x = c[0] * piglit_width;
			y = c[1] * piglit_width;
			if (x >= piglit_width)
				x = piglit_width - 1;
			if (y >= piglit_height)
				y = piglit_height - 1;

			if (!piglit_probe_pixel_rgba(x, y, &c[2])) {
915 916
				pass = false;
			}
917
		} else if (string_match("probe rgb", line)) {
918 919 920 921 922
			get_floats(line + 9, c, 5);
			if (!piglit_probe_pixel_rgb((int) c[0], (int) c[1],
						    & c[2])) {
				pass = false;
			}
923 924 925 926 927
		} else if (sscanf(line,
				  "relative probe rgb ( %f , %f ) "
				  "( %f , %f , %f )",
				  c + 0, c + 1,
				  c + 2, c + 3, c + 4) == 5) {
928 929 930 931 932 933 934 935
			x = c[0] * piglit_width;
			y = c[1] * piglit_width;
			if (x >= piglit_width)
				x = piglit_width - 1;
			if (y >= piglit_height)
				y = piglit_height - 1;

			if (!piglit_probe_pixel_rgb(x, y, &c[2])) {
936 937
				pass = false;
			}
938
		} else if (string_match("probe all rgba", line)) {
939
			get_floats(line + 14, c, 4);
940 941 942
			pass = pass &&
				piglit_probe_rect_rgba(0, 0, piglit_width,
						       piglit_height, c);
943
		} else if (string_match("probe all rgb", line)) {
944
			get_floats(line + 13, c, 3);
945 946 947
			pass = pass &&
				piglit_probe_rect_rgb(0, 0, piglit_width,
						      piglit_height, c);
948 949 950 951
		} else if (sscanf(line,
				  "texture rgbw %d ( %d , %d )",
				  &tex, &w, &h) == 3) {
			glActiveTexture(GL_TEXTURE0 + tex);
952
			piglit_rgbw_texture(GL_RGBA, w, h, GL_FALSE, GL_FALSE, GL_UNSIGNED_NORMALIZED);
953
			glEnable(GL_TEXTURE_2D);
954 955 956 957 958 959 960 961 962 963 964 965 966
		} else if (sscanf(line,
				  "texture checkerboard %d %d ( %d , %d ) "
				  "( %f , %f , %f , %f ) "
				  "( %f , %f , %f , %f )",
				  &tex, &level, &w, &h,
				  c + 0, c + 1, c + 2, c + 3,
				  c + 4, c + 5, c + 6, c + 7) == 12) {
			glActiveTexture(GL_TEXTURE0 + tex);
			piglit_checkerboard_texture(0, level,
						    w, h,
						    w / 2, h / 2,
						    c + 0, c + 4);
			glEnable(GL_TEXTURE_2D);
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
		} else if (sscanf(line,
				  "texture shadow %d ( %d , %d )",
				  &tex, &w, &h) == 3) {
			glActiveTexture(GL_TEXTURE0 + tex);
			piglit_depth_texture(GL_DEPTH_COMPONENT,
					     w, h, GL_FALSE);
			glTexParameteri(GL_TEXTURE_2D,
					GL_TEXTURE_COMPARE_MODE_ARB,
					GL_COMPARE_R_TO_TEXTURE_ARB);
			glTexParameteri(GL_TEXTURE_2D,
					GL_TEXTURE_COMPARE_FUNC_ARB,
					GL_GREATER);
			glTexParameteri(GL_TEXTURE_2D,
					GL_DEPTH_TEXTURE_MODE_ARB,
					GL_INTENSITY);

			glEnable(GL_TEXTURE_2D);
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
		} else if (!strncmp(line,
				    "texparameter compare_func greater\n",
				    34)) {
			glTexParameteri(GL_TEXTURE_2D,
					GL_TEXTURE_COMPARE_FUNC_ARB,
					GL_GREATER);
		} else if (!strncmp(line,
				    "texparameter compare_func always\n",
				    33)) {
			glTexParameteri(GL_TEXTURE_2D,
					GL_TEXTURE_COMPARE_FUNC_ARB,
					GL_ALWAYS);
		} else if (!strncmp(line,
				    "texparameter compare_func never\n",
				    32)) {
			glTexParameteri(GL_TEXTURE_2D,
					GL_TEXTURE_COMPARE_FUNC_ARB,
					GL_NEVER);
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
		} else if (!strncmp(line,
			           "texparameter depth_mode red\n",
			            28)) {
			/* Requires GL 3.0 or GL_ARB_texture_rg */
			glTexParameteri(GL_TEXTURE_2D,
				        GL_DEPTH_TEXTURE_MODE_ARB,
				        GL_RED);
		} else if (!strncmp(line,
			           "texparameter depth_mode luminance\n",
			            34)) {
			glTexParameteri(GL_TEXTURE_2D,
				        GL_DEPTH_TEXTURE_MODE_ARB,
				        GL_LUMINANCE);
		} else if (!strncmp(line,
			           "texparameter depth_mode intensity\n",
			            34)) {
			glTexParameteri(GL_TEXTURE_2D,
				        GL_DEPTH_TEXTURE_MODE_ARB,
				        GL_INTENSITY);
		} else if (!strncmp(line,
			           "texparameter depth_mode alpha\n",
			            29)) {
			glTexParameteri(GL_TEXTURE_2D,
				        GL_DEPTH_TEXTURE_MODE_ARB,
				        GL_ALPHA);
1027
		} else if (string_match("uniform", line)) {
1028 1029 1030 1031
			set_uniform(line + 7);
		} else if ((line[0] != '\n') && (line[0] != '\0')
			   && (line[0] != '#')) {
			printf("unknown command \"%s\"", line);
1032
			piglit_report_result(PIGLIT_FAIL);
1033 1034 1035 1036 1037 1038 1039 1040 1041
		}

		line = strchrnul(line, '\n');
		if (line[0] != '\0')
			line++;
	}

	glutSwapBuffers();

1042 1043
	if (piglit_automatic) {
		/* Free our resources, useful for valgrinding. */
1044 1045
		piglit_DeleteProgram(prog);
		piglit_UseProgram(0);
1046 1047
	}

1048
	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
1049 1050 1051 1052 1053 1054 1055 1056
}


void
piglit_init(int argc, char **argv)
{
	const char *glsl_version_string;

1057 1058
	piglit_require_GLSL();

1059
	gl_version = strtod((char *) glGetString(GL_VERSION), NULL);
1060 1061 1062 1063

	glsl_version_string = (char *)
		glGetString(GL_SHADING_LANGUAGE_VERSION);
	glsl_version = (glsl_version_string == NULL)
1064
		? 0.0 : strtod(glsl_version_string, NULL);
1065

1066 1067 1068 1069 1070
	glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS,
		      &gl_max_fragment_uniform_components);
	glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS,
		      &gl_max_vertex_uniform_components);

1071
	if (argc > 2) {
1072
		path = argv[2];
1073
	} else {
Jose Fonseca's avatar
Jose Fonseca committed
1074
#if defined(_WIN32)
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
		char drive[_MAX_DRIVE];
		char dir[_MAX_DIR];
		char fname[_MAX_FNAME];
		char ext[_MAX_EXT];
		char* scriptpath;
		_splitpath(argv[1], drive, dir, fname, ext);
		scriptpath = malloc(strlen(drive) + strlen(dir) + 1);
		strcpy(scriptpath, drive);
		strcat(scriptpath, dir);
		path = scriptpath;
#else
1086 1087 1088 1089 1090
		/* Because dirname()'s memory handling is unpredictable, we
		 * must copy both its input and ouput. */
		char* scriptpath = strdup(argv[1]);
		path = strdup(dirname(scriptpath));
		free(scriptpath);
1091
#endif
1092
	}
1093

1094 1095 1096
	process_test_script(argv[1]);
	link_and_use_shaders();
}