Random state-change / primitive rendering. Good for hammering on a driver...
[mesa.git] / progs / tests / random.c
1 /**
2 * Random rendering, to check for crashes, hangs, etc.
3 *
4 * Brian Paul
5 * 21 June 2007
6 */
7
8 #define GL_GLEXT_PROTOTYPES
9
10 #include <assert.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 #include <GL/glut.h>
16
17 static int Win;
18 static GLboolean Anim = GL_TRUE;
19 static int Width = 200, Height = 200;
20 static int DB = 0;
21 static int MinVertexCount = 0, MaxVertexCount = 1000;
22 static int Count = 0;
23
24 struct vertex
25 {
26 int type;
27 float v[4];
28 };
29
30 static int BufferSize = 10000;
31 static struct vertex *Vbuffer = NULL;
32 static int Vcount, Vprim;
33
34 enum {
35 BEGIN,
36 END,
37 VERTEX2,
38 VERTEX3,
39 VERTEX4,
40 COLOR3,
41 COLOR4,
42 TEX2,
43 TEX3,
44 TEX4,
45 SECCOLOR3,
46 NORMAL3
47 };
48
49
50
51 /**
52 * This can be called from within gdb after a crash:
53 * (gdb) call ReportState()
54 */
55 static void
56 ReportState(void)
57 {
58 static const struct {
59 GLenum token;
60 char *str;
61 GLenum type;
62 } state [] = {
63 { GL_ALPHA_TEST, "GL_ALPHA_TEST", GL_INT },
64 { GL_BLEND, "GL_BLEND", GL_INT },
65 { GL_CLIP_PLANE0, "GL_CLIP_PLANE0", GL_INT },
66 { GL_DEPTH_TEST, "GL_DEPTH_TEST", GL_INT },
67 { GL_LIGHTING, "GL_LIGHTING", GL_INT },
68 { GL_LINE_WIDTH, "GL_LINE_WIDTH", GL_FLOAT },
69 { GL_POINT_SIZE, "GL_POINT_SIZE", GL_FLOAT },
70 { GL_SHADE_MODEL, "GL_SHADE_MODEL", GL_INT },
71 { GL_SCISSOR_TEST, "GL_SCISSOR_TEST", GL_INT },
72 { 0, NULL, 0 }
73 };
74
75 GLint i;
76
77 for (i = 0; state[i].token; i++) {
78 if (state[i].type == GL_INT) {
79 GLint v;
80 glGetIntegerv(state[i].token, &v);
81 printf("%s = %d\n", state[i].str, v);
82 }
83 else {
84 GLfloat v;
85 glGetFloatv(state[i].token, &v);
86 printf("%s = %f\n", state[i].str, v);
87 }
88 }
89 }
90
91 static void
92 PrintVertex(const char *f, const struct vertex *v, int sz)
93 {
94 int i;
95 printf("%s(", f);
96 for (i = 0; i < sz; i++) {
97 printf("%g%s", v->v[i], (i == sz-1) ? "" : ", ");
98 }
99 printf(");\n");
100 }
101
102 /**
103 * This can be called from within gdb after a crash:
104 * (gdb) call ReportState()
105 */
106 static void
107 LastPrim(void)
108 {
109 int i;
110 for (i = 0; i < Vcount; i++) {
111 switch (Vbuffer[i].type) {
112 case BEGIN:
113 printf("glBegin(%d);\n", (int) Vbuffer[i].v[0]);
114 break;
115 case END:
116 printf("glEnd();\n");
117 break;
118 case VERTEX2:
119 PrintVertex("glVertex2f", Vbuffer + i, 2);
120 break;
121 case VERTEX3:
122 PrintVertex("glVertex3f", Vbuffer + i, 3);
123 break;
124 case VERTEX4:
125 PrintVertex("glVertex4f", Vbuffer + i, 4);
126 break;
127 case COLOR3:
128 PrintVertex("glColor3f", Vbuffer + i, 3);
129 break;
130 case COLOR4:
131 PrintVertex("glColor4f", Vbuffer + i, 4);
132 break;
133 case TEX2:
134 PrintVertex("glTexCoord2f", Vbuffer + i, 2);
135 break;
136 case TEX3:
137 PrintVertex("glTexCoord3f", Vbuffer + i, 3);
138 break;
139 case TEX4:
140 PrintVertex("glTexCoord4f", Vbuffer + i, 4);
141 break;
142 case SECCOLOR3:
143 PrintVertex("glSecondaryColor3f", Vbuffer + i, 3);
144 break;
145 case NORMAL3:
146 PrintVertex("glNormal3f", Vbuffer + i, 3);
147 break;
148 default:
149 abort();
150 }
151 }
152 }
153
154
155 static int
156 RandomInt(int max)
157 {
158 if (max == 0)
159 return 0;
160 return rand() % max;
161 }
162
163 static float
164 RandomFloat(float min, float max)
165 {
166 int k = rand() % 10000;
167 float x = min + (max - min) * k / 10000.0;
168 return x;
169 }
170
171 /*
172 * Return true if random number in [0,1] is <= percentile.
173 */
174 static GLboolean
175 RandomChoice(float percentile)
176 {
177 return RandomFloat(0.0, 1.0) <= percentile;
178 }
179
180 static void
181 RandomStateChange(void)
182 {
183 int k = RandomInt(19);
184 switch (k) {
185 case 0:
186 glEnable(GL_BLEND);
187 break;
188 case 1:
189 glDisable(GL_BLEND);
190 break;
191 case 2:
192 glEnable(GL_ALPHA_TEST);
193 break;
194 case 3:
195 glEnable(GL_ALPHA_TEST);
196 break;
197 case 4:
198 glEnable(GL_DEPTH_TEST);
199 break;
200 case 5:
201 glEnable(GL_DEPTH_TEST);
202 break;
203 case 6:
204 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
205 break;
206 case 7:
207 glPointSize(10.0);
208 break;
209 case 8:
210 glPointSize(1.0);
211 break;
212 case 9:
213 glLineWidth(10.0);
214 break;
215 case 10:
216 glLineWidth(1.0);
217 break;
218 case 11:
219 glEnable(GL_LIGHTING);
220 break;
221 case 12:
222 glDisable(GL_LIGHTING);
223 break;
224 case 13:
225 glEnable(GL_SCISSOR_TEST);
226 break;
227 case 14:
228 glDisable(GL_SCISSOR_TEST);
229 break;
230 case 15:
231 glEnable(GL_CLIP_PLANE0);
232 break;
233 case 16:
234 glDisable(GL_CLIP_PLANE0);
235 break;
236 case 17:
237 glShadeModel(GL_FLAT);
238 break;
239 case 18:
240 glShadeModel(GL_SMOOTH);
241 break;
242 }
243 }
244
245
246 static void
247 RandomPrimitive(void)
248 {
249 int i;
250 int len = MinVertexCount + RandomInt(MaxVertexCount - MinVertexCount);
251
252 Vprim = RandomInt(10);
253
254 glBegin(Vprim);
255 Vbuffer[Vcount].type = BEGIN;
256 Vbuffer[Vcount].v[0] = Vprim;
257 Vcount++;
258
259 for (i = 0; i < len; i++) {
260 Vbuffer[Vcount].v[0] = RandomFloat(-3, 3);
261 Vbuffer[Vcount].v[1] = RandomFloat(-3, 3);
262 Vbuffer[Vcount].v[2] = RandomFloat(-3, 3);
263 Vbuffer[Vcount].v[3] = RandomFloat(-3, 3);
264 int k = RandomInt(9);
265 switch (k) {
266 case 0:
267 glVertex2fv(Vbuffer[Vcount].v);
268 Vbuffer[Vcount].type = VERTEX2;
269 break;
270 case 1:
271 glVertex3fv(Vbuffer[Vcount].v);
272 Vbuffer[Vcount].type = VERTEX3;
273 break;
274 case 2:
275 glVertex4fv(Vbuffer[Vcount].v);
276 Vbuffer[Vcount].type = VERTEX4;
277 break;
278 case 3:
279 glColor3fv(Vbuffer[Vcount].v);
280 Vbuffer[Vcount].type = COLOR3;
281 break;
282 case 4:
283 glColor4fv(Vbuffer[Vcount].v);
284 Vbuffer[Vcount].type = COLOR4;
285 break;
286 case 5:
287 glTexCoord2fv(Vbuffer[Vcount].v);
288 Vbuffer[Vcount].type = TEX2;
289 break;
290 case 6:
291 glTexCoord3fv(Vbuffer[Vcount].v);
292 Vbuffer[Vcount].type = TEX3;
293 break;
294 case 7:
295 glTexCoord4fv(Vbuffer[Vcount].v);
296 Vbuffer[Vcount].type = TEX4;
297 break;
298 case 8:
299 glSecondaryColor3fv(Vbuffer[Vcount].v);
300 Vbuffer[Vcount].type = SECCOLOR3;
301 break;
302 case 9:
303 glNormal3fv(Vbuffer[Vcount].v);
304 Vbuffer[Vcount].type = NORMAL3;
305 break;
306 default:
307 abort();
308 }
309 Vcount++;
310
311 if (Vcount >= BufferSize - 2) {
312 /* reset */
313 Vcount = 0;
314 }
315 }
316
317 Vbuffer[Vcount++].type = END;
318
319 glEnd();
320 }
321
322
323 static void
324 RandomDraw(void)
325 {
326 int i;
327 GLboolean dlist = RandomChoice(0.1);
328 if (dlist)
329 glNewList(1, GL_COMPILE);
330 for (i = 0; i < 3; i++) {
331 RandomStateChange();
332 }
333 RandomPrimitive();
334
335 if (dlist) {
336 glEndList();
337 glCallList(1);
338 }
339 }
340
341
342 static void
343 Idle(void)
344 {
345 glutPostRedisplay();
346 }
347
348
349 static void
350 Draw(void)
351 {
352 #if 1
353 RandomDraw();
354 Count++;
355 #else
356 /* cut & paste temp code here */
357 #endif
358
359 assert(glGetError() == 0);
360
361 if (DB)
362 glutSwapBuffers();
363 else
364 glFinish();
365 }
366
367
368 static void
369 Reshape(int width, int height)
370 {
371 Width = width;
372 Height = height;
373 glViewport(0, 0, width, height);
374 glScissor(20, 20, Width-40, Height-40);
375 glMatrixMode(GL_PROJECTION);
376 glLoadIdentity();
377 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
378 glMatrixMode(GL_MODELVIEW);
379 glLoadIdentity();
380 glTranslatef(0.0, 0.0, -15.0);
381 }
382
383
384 static void
385 Key(unsigned char key, int x, int y)
386 {
387 (void) x;
388 (void) y;
389 switch (key) {
390 case 27:
391 glutDestroyWindow(Win);
392 exit(0);
393 break;
394 }
395 glutPostRedisplay();
396 }
397
398
399 static void
400 Init(void)
401 {
402 static const GLdouble plane[4] = {1, 1, 0, 0};
403 glDrawBuffer(GL_FRONT);
404 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
405 glEnable(GL_LIGHT0);
406 glClipPlane(GL_CLIP_PLANE0, plane);
407
408 Vbuffer = (struct vertex *)
409 malloc(BufferSize * sizeof(struct vertex));
410
411 /* silence warnings */
412 (void) ReportState;
413 (void) LastPrim;
414 }
415
416
417 static void
418 ParseArgs(int argc, char *argv[])
419 {
420 int i;
421 for (i = 1; i < argc; i++) {
422 if (strcmp(argv[i], "-s") == 0) {
423 int j = atoi(argv[i + 1]);
424 printf("Random seed value: %d\n", j);
425 srand(j);
426 i++;
427 }
428 else if (strcmp(argv[i], "-a") == 0) {
429 i++;
430 MinVertexCount = atoi(argv[i]);
431 }
432 else if (strcmp(argv[i], "-b") == 0) {
433 i++;
434 MaxVertexCount = atoi(argv[i]);
435 }
436 }
437 }
438
439
440 int
441 main(int argc, char *argv[])
442 {
443 glutInit(&argc, argv);
444 glutInitWindowPosition(0, 0);
445 glutInitWindowSize(Width, Height);
446 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
447 Win = glutCreateWindow(argv[0]);
448 ParseArgs(argc, argv);
449 glutReshapeFunc(Reshape);
450 glutKeyboardFunc(Key);
451 glutDisplayFunc(Draw);
452 if (Anim)
453 glutIdleFunc(Idle);
454 Init();
455 glutMainLoop();
456 return 0;
457 }