1 /*
2  * Copyright (c) 2009 Nicolai Hähnle
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  * Authors:
24  *    Nicolai Hähnle <nhaehnle@gmail.com>
25  *
26  */
27 
28 /**
29  * \file
30  * Test certain type of very long fragment programs.
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "piglit-util-gl.h"
38 
39 PIGLIT_GL_TEST_CONFIG_BEGIN
40 
41 	config.supports_gl_compat_version = 10;
42 
43 	config.window_visual = PIGLIT_GL_VISUAL_RGBA;
44 
45 PIGLIT_GL_TEST_CONFIG_END
46 
47 int max_alu_instructions;
48 
49 static const char program_Head[] =
50 	"!!ARBfp1.0\n"
51 	"TEMP r;\n"
52 	"MOV r, 0;\n"
53 	;
54 
55 static const char program_Step[] = "ADD %s, r.wxyz, { %f, %f, %f, %f };\n";
56 
57 static const char program_Tail[] =
58 	"END\n";
59 
60 static const char program_Output[] = "result.color";
61 
step_add(unsigned int i,float * add)62 static void step_add(unsigned int i, float * add)
63 {
64 	unsigned int rotate = i % 4;
65 	add[(0 + rotate) % 4] = ((i+1) % 16) ? 0.0625 : -1.0+0.0625;
66 	add[(1 + rotate) % 4] = ((i+1) % 16) ? 0.0 : (((i+1) % 256) ? 0.0625 : -1.0+0.0625);
67 	add[(2 + rotate) % 4] = ((i+1) % 256) ? 0.0 : (((i+1) % 4096) ? 0.0625 : -1.0+0.0625);
68 	add[(3 + rotate) % 4] = ((i+1) % 4096) ? 0.0 : 0.0625;
69 }
70 
test(unsigned int alu_depth)71 static enum piglit_result test(unsigned int alu_depth)
72 {
73 	char * program_text = malloc(sizeof(program_Head) +
74 	                             2*alu_depth*sizeof(program_Step) +
75 	                             sizeof(program_Tail) +
76 	                             sizeof(program_Output));
77 	char * buildp;
78 	char buf[128];
79 	GLuint program_object;
80 	unsigned int i;
81 	float expected[4] = { 0.0, 0.0, 0.0, 0.0 };
82 
83 	/* Note: This test makes sense up to alu_depth of 65536,
84 	 * but current drivers are not exactly efficient with such
85 	 * long programs, and if 16k works, then 64k will probably
86 	 * work, too ;-)
87 	 */
88 	if (!alu_depth || alu_depth > 16384 || alu_depth + 1 > max_alu_instructions) {
89 		free(program_text);
90 		return PIGLIT_SKIP;
91 	}
92 
93 	printf("Testing: alu_depth = %u\n", alu_depth);
94 
95 	memcpy(program_text, program_Head, sizeof(program_Head)-1);
96 	buildp = program_text + sizeof(program_Head)-1;
97 
98 	for(i = 0; i < alu_depth; ++i) {
99 		float add[4];
100 		int length;
101 		step_add(i, add);
102 		length = snprintf(buf, sizeof(buf),
103 			program_Step, i == (alu_depth-1) ? program_Output : "r",
104 			add[0], add[1], add[2], add[3]);
105 		memcpy(buildp, buf, length);
106 		buildp += length;
107 	}
108 	memcpy(buildp, program_Tail, sizeof(program_Tail));
109 
110 //	printf(program_text);
111 
112 	program_object = piglit_compile_program(GL_FRAGMENT_PROGRAM_ARB, program_text);
113 	free(program_text);
114 	program_text = NULL;
115 
116 	glEnable(GL_FRAGMENT_PROGRAM_ARB);
117 	glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_object);
118 
119 	piglit_draw_rect(0, 0, 32, 32);
120 
121 	glDisable(GL_FRAGMENT_PROGRAM_ARB);
122 	glDeleteProgramsARB(1, &program_object);
123 
124 	expected[0] = (alu_depth % 16) * 0.0625;
125 	expected[1] = ((alu_depth/16) % 16) * 0.0625;
126 	expected[2] = ((alu_depth/256) % 16) * 0.0625;
127 	expected[3] = (alu_depth/4096) * 0.0625;
128 	for(i = 0; i < ((alu_depth+3) % 4); ++i) {
129 		float tmp = expected[3];
130 		expected[3] = expected[2];
131 		expected[2] = expected[1];
132 		expected[1] = expected[0];
133 		expected[0] = tmp;
134 	}
135 	if (expected[0] > 1.0)
136 		expected[0] = 1.0;
137 	if (expected[1] > 1.0)
138 		expected[1] = 1.0;
139 	if (expected[2] > 1.0)
140 		expected[2] = 1.0;
141 	if (expected[3] > 1.0)
142 		expected[3] = 1.0;
143 
144 	if (!piglit_probe_pixel_rgba(16, 16, expected)) {
145 		fprintf(stderr, "Failure in alu_depth = %i\n", alu_depth);
146 		return PIGLIT_FAIL;
147 	}
148 
149 	return PIGLIT_PASS;
150 }
151 
piglit_display(void)152 enum piglit_result piglit_display(void)
153 {
154 	enum piglit_result result;
155 	unsigned int alu_depth;
156 
157 	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
158 	glClear(GL_COLOR_BUFFER_BIT);
159 
160 	alu_depth = 1;
161 	for(;;) {
162 		result = test(alu_depth);
163 		if (result == PIGLIT_SKIP)
164 			break;
165 		if (result != PIGLIT_PASS)
166 			return result;
167 
168 		if (alu_depth < 8) {
169 			alu_depth++;
170 		} else {
171 			/* Not quite powers of two to avoid aliasing */
172 			alu_depth = (alu_depth * 2) - 5;
173 		}
174 	}
175 
176 	return PIGLIT_PASS;
177 }
178 
179 
piglit_init(int argc,char ** argv)180 void piglit_init(int argc, char ** argv)
181 {
182 	piglit_require_fragment_program();
183 
184 	glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
185 			  GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB,
186 			  &max_alu_instructions);
187 
188 	printf("Max (native) ALU instructions: %i\n",
189 	       max_alu_instructions);
190 }
191