Add more structure constructor tests.
[piglit/hramrach.git] / tests / util / piglit-util.c
blobec0488ab8a3463f9c7957c1d08ce33d6241c0746
1 /*
2 * Copyright (c) The Piglit project 2007
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
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.
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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #if defined(_MSC_VER)
25 #include <windows.h>
26 #endif
28 #include <assert.h>
29 #include <math.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/stat.h>
36 #include "piglit-util.h"
38 /* These texture coordinates should have 1 or -1 in the major axis selecting
39 * the face, and a nearly-1-or-negative-1 value in the other two coordinates
40 * which will be used to produce the s,t values used to sample that face's
41 * image.
43 GLfloat cube_face_texcoords[6][4][3] = {
44 { /* GL_TEXTURE_CUBE_MAP_POSITIVE_X */
45 {1.0, 0.99, 0.99},
46 {1.0, 0.99, -0.99},
47 {1.0, -0.99, -0.99},
48 {1.0, -0.99, 0.99},
50 { /* GL_TEXTURE_CUBE_MAP_POSITIVE_Y */
51 {-0.99, 1.0, -0.99},
52 { 0.99, 1.0, -0.99},
53 { 0.99, 1.0, 0.99},
54 {-0.99, 1.0, 0.99},
56 { /* GL_TEXTURE_CUBE_MAP_POSITIVE_Z */
57 {-0.99, 0.99, 1.0},
58 {-0.99, -0.99, 1.0},
59 { 0.99, -0.99, 1.0},
60 { 0.99, 0.99, 1.0},
62 { /* GL_TEXTURE_CUBE_MAP_NEGATIVE_X */
63 {-1.0, 0.99, -0.99},
64 {-1.0, 0.99, 0.99},
65 {-1.0, -0.99, 0.99},
66 {-1.0, -0.99, -0.99},
68 { /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Y */
69 {-0.99, -1.0, 0.99},
70 {-0.99, -1.0, -0.99},
71 { 0.99, -1.0, -0.99},
72 { 0.99, -1.0, 0.99},
74 { /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z */
75 { 0.99, 0.99, -1.0},
76 {-0.99, 0.99, -1.0},
77 {-0.99, -0.99, -1.0},
78 { 0.99, -0.99, -1.0},
82 const char *cube_face_names[6] = {
83 "POSITIVE_X",
84 "POSITIVE_Y",
85 "POSITIVE_Z",
86 "NEGATIVE_X",
87 "NEGATIVE_Y",
88 "NEGATIVE_Z",
91 const GLenum cube_face_targets[6] = {
92 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
93 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
94 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
95 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
96 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
97 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
100 GLint piglit_ARBfp_pass_through = 0;
102 /** Returns the line in the program string given the character position. */
103 int FindLine(const char *program, int position)
105 int i, line = 1;
106 for (i = 0; i < position; i++) {
107 if (program[i] == '0')
108 return -1; /* unknown line */
109 if (program[i] == '\n')
110 line++;
112 return line;
115 void
116 piglit_report_result(enum piglit_result result)
118 fflush(stderr);
120 if (result == PIGLIT_SUCCESS) {
121 printf("PIGLIT: {'result': 'pass' }\n");
122 fflush(stdout);
123 exit(0);
124 } else if (result == PIGLIT_SKIP) {
125 printf("PIGLIT: {'result': 'skip' }\n");
126 fflush(stdout);
127 exit(0);
128 } else if (result == PIGLIT_WARN) {
129 printf("PIGLIT: {'result': 'warn' }\n");
130 fflush(stdout);
131 exit(0);
132 } else {
133 printf("PIGLIT: {'result': 'fail' }\n");
134 fflush(stdout);
135 exit(1);
139 void piglit_require_extension(const char *name)
141 if (!glutExtensionSupported(name)) {
142 piglit_report_result(PIGLIT_SKIP);
143 exit(1);
147 void piglit_require_not_extension(const char *name)
149 if (glutExtensionSupported(name)) {
150 piglit_report_result(PIGLIT_SKIP);
151 exit(1);
156 * Read a pixel from the given location and compare its RGBA value to the
157 * given expected values.
159 * Print a log message if the color value deviates from the expected value.
160 * \return true if the color values match, false otherwise
162 int piglit_probe_pixel_rgba(int x, int y, const float* expected)
164 GLfloat probe[4];
165 GLfloat delta[4];
166 GLfloat deltamax;
167 int i;
169 glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, probe);
171 deltamax = 0.0;
172 for(i = 0; i < 4; ++i) {
173 delta[i] = probe[i] - expected[i];
174 if (fabs(delta[i]) > deltamax)
175 deltamax = fabs(delta[i]);
178 if (deltamax < 0.01)
179 return 1;
181 printf("Probe at (%i,%i)\n", x, y);
182 printf(" Expected: %f %f %f %f\n", expected[0], expected[1], expected[2], expected[3]);
183 printf(" Observed: %f %f %f %f\n", probe[0], probe[1], probe[2], probe[3]);
185 return 0;
189 piglit_probe_rect_rgba(int x, int y, int w, int h, const float *expected)
191 int i, j;
193 for (i = 0; i < w; i++) {
194 for (j = 0; j < h; j++) {
195 if (!piglit_probe_pixel_rgba(i, j, expected))
196 return 1;
200 return 0;
204 * Read a pixel from the given location and compare its RGB value to the
205 * given expected values.
207 * Print a log message if the color value deviates from the expected value.
208 * \return true if the color values match, false otherwise
210 int piglit_probe_pixel_rgb(int x, int y, const float* expected)
212 GLfloat probe[3];
213 GLfloat delta[3];
214 GLfloat deltamax;
215 int i;
217 glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, probe);
219 deltamax = 0.0;
220 for(i = 0; i < 3; ++i) {
221 delta[i] = probe[i] - expected[i];
222 if (fabs(delta[i]) > deltamax)
223 deltamax = fabs(delta[i]);
226 if (deltamax < 0.01)
227 return 1;
229 printf("Probe at (%i,%i)\n", x, y);
230 printf(" Expected: %f %f %f\n", expected[0], expected[1], expected[2]);
231 printf(" Observed: %f %f %f\n", probe[0], probe[1], probe[2]);
233 return 0;
237 piglit_probe_rect_rgb(int x, int y, int w, int h, const float *expected)
239 int i, j;
241 for (i = 0; i < w; i++) {
242 for (j = 0; j < h; j++) {
243 if (!piglit_probe_pixel_rgb(i, j, expected))
244 return 1;
248 return 0;
252 * Read a pixel from the given location and compare its depth value to the
253 * given expected value.
255 * Print a log message if the depth value deviates from the expected value.
256 * \return true if the depth value matches, false otherwise
258 int piglit_probe_pixel_depth(int x, int y, float expected)
260 GLfloat probe;
261 GLfloat delta;
263 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &probe);
265 delta = probe - expected;
266 if (fabs(delta) < 0.01)
267 return 1;
269 printf("Probe at (%i,%i)\n", x, y);
270 printf(" Expected: %f\n", expected);
271 printf(" Observed: %f\n", probe);
273 return 0;
277 * Read a texel from the given location and compare its RGBA value to the
278 * given expected values.
280 * Print a log message if the color value deviates from the expected value.
281 * \return true if the color values match, false otherwise
283 int piglit_probe_texel_rgba(int target, int level, int x, int y,
284 const float* expected)
286 GLfloat *buffer;
287 GLfloat *probe;
288 GLfloat delta[4];
289 GLfloat deltamax;
290 int i;
291 GLint width;
292 GLint height;
294 glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
295 glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
296 buffer = malloc(width * height * 4 * sizeof(GLfloat));
298 glGetTexImage(target, level, GL_RGBA, GL_FLOAT, buffer);
300 probe = &buffer[4 * ((width * y) + x)];
301 deltamax = 0.0;
302 for(i = 0; i < 4; ++i) {
303 delta[i] = probe[i] - expected[i];
304 if (fabs(delta[i]) > deltamax)
305 deltamax = fabs(delta[i]);
308 if (deltamax < 0.01) {
309 free(buffer);
310 return 1;
313 printf("Probe at (%i,%i)\n", x, y);
314 printf(" Expected: %f %f %f %f\n", expected[0], expected[1], expected[2], expected[3]);
315 printf(" Observed: %f %f %f %f\n", probe[0], probe[1], probe[2], probe[3]);
317 free(buffer);
318 return 0;
322 * Read a texel from the given location and compare its RGBA value to the
323 * given expected values.
325 * Print a log message if the color value deviates from the expected value.
326 * \return true if the color values match, false otherwise
328 int piglit_probe_texel_rgb(int target, int level, int x, int y,
329 const float* expected)
331 GLfloat *buffer;
332 GLfloat *probe;
333 GLfloat delta[3];
334 GLfloat deltamax;
335 int i;
336 GLint width;
337 GLint height;
339 glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
340 glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
341 buffer = malloc(width * height * 3 * sizeof(GLfloat));
343 glGetTexImage(target, level, GL_RGB, GL_FLOAT, buffer);
345 probe = &buffer[3 * ((width * y) + x)];
346 deltamax = 0.0;
347 for(i = 0; i < 3; ++i) {
348 delta[i] = probe[i] - expected[i];
349 if (fabs(delta[i]) > deltamax)
350 deltamax = fabs(delta[i]);
353 if (deltamax < 0.01) {
354 free(buffer);
355 return 1;
358 printf("Probe at (%i,%i)\n", x, y);
359 printf(" Expected: %f %f %f\n", expected[0], expected[1], expected[2]);
360 printf(" Observed: %f %f %f\n", probe[0], probe[1], probe[2]);
362 free(buffer);
363 return 0;
366 int piglit_use_fragment_program(void)
368 static const char source[] =
369 "!!ARBfp1.0\n"
370 "MOV result.color, fragment.color;\n"
371 "END\n"
374 glewInit();
375 if (!GLEW_ARB_fragment_program)
376 return 0;
378 piglit_ARBfp_pass_through =
379 piglit_compile_program(GL_FRAGMENT_PROGRAM_ARB, source);
381 return (piglit_ARBfp_pass_through != 0);
384 void piglit_require_fragment_program(void)
386 if (!piglit_use_fragment_program()) {
387 printf("GL_ARB_fragment_program not supported.\n");
388 piglit_report_result(PIGLIT_SKIP);
389 exit(1);
393 int piglit_use_vertex_program(void)
395 glewInit();
396 return GLEW_ARB_vertex_program;
399 void piglit_require_vertex_program(void)
401 if (!piglit_use_vertex_program()) {
402 printf("GL_ARB_vertex_program not supported.\n");
403 piglit_report_result(PIGLIT_SKIP);
404 exit(1);
408 GLuint piglit_compile_program(GLenum target, const char* text)
410 GLuint program;
411 GLint errorPos;
413 glGenProgramsARB(1, &program);
414 glBindProgramARB(target, program);
415 glProgramStringARB(
416 target,
417 GL_PROGRAM_FORMAT_ASCII_ARB,
418 strlen(text),
419 (const GLubyte *)text);
420 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
421 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
422 int l = FindLine(text, errorPos);
423 int a;
425 fprintf(stderr, "Compiler Error (pos=%d line=%d): %s\n",
426 errorPos, l,
427 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
429 for (a=-10; a<10; a++)
431 if (errorPos+a < 0)
432 continue;
433 if (errorPos+a >= strlen(text))
434 break;
435 fprintf(stderr, "%c", text[errorPos+a]);
437 fprintf(stderr, "\nin program:\n%s", text);
438 piglit_report_result(PIGLIT_FAILURE);
440 if (!glIsProgramARB(program)) {
441 fprintf(stderr, "glIsProgramARB failed\n");
442 piglit_report_result(PIGLIT_FAILURE);
445 return program;
449 * Convenience function to compile a GLSL shader from a file.
451 GLuint
452 piglit_compile_shader(GLenum target, char *filename)
454 GLuint prog;
455 struct stat st;
456 int err;
457 GLchar *prog_string;
458 FILE *f;
459 const char *source_dir;
460 char filename_with_path[FILENAME_MAX];
462 source_dir = getenv("PIGLIT_SOURCE_DIR");
463 if (source_dir == NULL) {
464 source_dir = SOURCE_DIR;
467 snprintf(filename_with_path, FILENAME_MAX - 1,
468 "%s/tests/%s", source_dir, filename);
469 filename_with_path[FILENAME_MAX - 1] = 0;
471 err = stat(filename_with_path, &st);
472 if (err == -1) {
473 fprintf(stderr, "Couldn't stat program %s: %s\n", filename, strerror(errno));
474 fprintf(stderr, "You can override the source dir by setting the PIGLIT_SOURCE_DIR environment variable.\n");
475 exit(1);
478 prog_string = malloc(st.st_size + 1);
479 if (prog_string == NULL) {
480 fprintf(stderr, "malloc\n");
481 exit(1);
484 f = fopen(filename_with_path, "r");
485 if (f == NULL) {
486 fprintf(stderr, "Couldn't open program: %s\n", strerror(errno));
487 exit(1);
489 fread(prog_string, 1, st.st_size, f);
490 prog_string[st.st_size] = '\0';
491 fclose(f);
493 prog = piglit_compile_shader_text(target, prog_string);
495 free(prog_string);
497 return prog;
501 * Convenience function to compile a GLSL shader.
503 GLuint
504 piglit_compile_shader_text(GLenum target, const char *text)
506 GLuint prog;
507 GLint ok;
509 prog = glCreateShader(target);
510 glShaderSource(prog, 1, (const GLchar **) &text, NULL);
511 glCompileShader(prog);
513 glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
516 GLchar *info;
517 GLint size;
519 glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
520 info = malloc(size);
522 glGetShaderInfoLog(prog, size, NULL, info);
523 if (!ok) {
524 fprintf(stderr, "Failed to compile %s: %s\n",
525 target == GL_FRAGMENT_SHADER ? "FS" : "VS",
526 info);
528 else if (0) {
529 /* Enable this to get extra compilation info.
530 * Even if there's no compilation errors, the info
531 * log may have some remarks.
533 fprintf(stderr, "Shader compiler warning: %s\n", info);
535 free(info);
538 return prog;
541 GLboolean
542 piglit_link_check_status(GLint prog)
544 GLchar *info;
545 GLint size;
546 GLint ok;
548 glGetProgramiv(prog, GL_LINK_STATUS, &ok);
550 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
551 info = malloc(size);
553 glGetProgramInfoLog(prog, size, NULL, info);
554 if (!ok) {
555 fprintf(stderr, "Failed to link: %s\n", info);
557 else if (0) {
558 /* Enable this to get extra linking info.
559 * Even if there's no link errors, the info log may
560 * have some remarks.
562 fprintf(stderr, "Linker warning: %s\n", info);
565 free(info);
567 return ok;
570 GLint piglit_link_simple_program(GLint vs, GLint fs)
572 GLint prog;
574 prog = glCreateProgram();
575 if (fs)
576 glAttachShader(prog, fs);
577 if (vs)
578 glAttachShader(prog, vs);
579 glLinkProgram(prog);
581 piglit_link_check_status(prog);
583 return prog;
586 void
587 piglit_escape_exit_key(unsigned char key, int x, int y)
589 (void) x;
590 (void) y;
591 switch (key) {
592 case 27:
593 exit(0);
594 break;
596 glutPostRedisplay();
600 * Convenience function to draw an axis-aligned rectangle.
602 GLvoid
603 piglit_draw_rect(float x, float y, float w, float h)
605 float verts[4][4];
607 verts[0][0] = x;
608 verts[0][1] = y;
609 verts[0][2] = 0.0;
610 verts[0][3] = 1.0;
611 verts[1][0] = x + w;
612 verts[1][1] = y;
613 verts[1][2] = 0.0;
614 verts[1][3] = 1.0;
615 verts[2][0] = x + w;
616 verts[2][1] = y + h;
617 verts[2][2] = 0.0;
618 verts[2][3] = 1.0;
619 verts[3][0] = x;
620 verts[3][1] = y + h;
621 verts[3][2] = 0.0;
622 verts[3][3] = 1.0;
624 glVertexPointer(4, GL_FLOAT, 0, verts);
625 glEnableClientState(GL_VERTEX_ARRAY);
627 glDrawArrays(GL_QUADS, 0, 4);
629 glDisableClientState(GL_VERTEX_ARRAY);
633 * Convenience function to draw an axis-aligned rectangle.
635 GLvoid
636 piglit_draw_rect_z(float z, float x, float y, float w, float h)
638 float verts[4][4];
640 verts[0][0] = x;
641 verts[0][1] = y;
642 verts[0][2] = z;
643 verts[0][3] = 1.0;
644 verts[1][0] = x + w;
645 verts[1][1] = y;
646 verts[1][2] = z;
647 verts[1][3] = 1.0;
648 verts[2][0] = x + w;
649 verts[2][1] = y + h;
650 verts[2][2] = z;
651 verts[2][3] = 1.0;
652 verts[3][0] = x;
653 verts[3][1] = y + h;
654 verts[3][2] = z;
655 verts[3][3] = 1.0;
657 glVertexPointer(4, GL_FLOAT, 0, verts);
658 glEnableClientState(GL_VERTEX_ARRAY);
660 glDrawArrays(GL_QUADS, 0, 4);
662 glDisableClientState(GL_VERTEX_ARRAY);
666 * Convenience function to draw an axis-aligned rectangle
667 * with texture coordinates.
669 GLvoid
670 piglit_draw_rect_tex(float x, float y, float w, float h,
671 float tx, float ty, float tw, float th)
673 float verts[4][4];
674 float tex[4][2];
676 verts[0][0] = x;
677 verts[0][1] = y;
678 verts[0][2] = 0.0;
679 verts[0][3] = 1.0;
680 tex[0][0] = tx;
681 tex[0][1] = ty;
682 verts[1][0] = x + w;
683 verts[1][1] = y;
684 verts[1][2] = 0.0;
685 verts[1][3] = 1.0;
686 tex[1][0] = tx + tw;
687 tex[1][1] = ty;
688 verts[2][0] = x + w;
689 verts[2][1] = y + h;
690 verts[2][2] = 0.0;
691 verts[2][3] = 1.0;
692 tex[2][0] = tx + tw;
693 tex[2][1] = ty + th;
694 verts[3][0] = x;
695 verts[3][1] = y + h;
696 verts[3][2] = 0.0;
697 verts[3][3] = 1.0;
698 tex[3][0] = tx;
699 tex[3][1] = ty + th;
701 glVertexPointer(4, GL_FLOAT, 0, verts);
702 glTexCoordPointer(2, GL_FLOAT, 0, tex);
703 glEnableClientState(GL_VERTEX_ARRAY);
704 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
706 glDrawArrays(GL_QUADS, 0, 4);
708 glDisableClientState(GL_VERTEX_ARRAY);
709 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
714 * Convenience function to configure projection matrix for window coordinates
716 void
717 piglit_ortho_projection(int w, int h, GLboolean push)
719 /* Set up projection matrix so we can just draw using window
720 * coordinates.
722 glMatrixMode(GL_PROJECTION);
723 glLoadIdentity();
724 if (push)
725 glPushMatrix();
726 glOrtho(0, w, 0, h, -1, 1);
728 glMatrixMode(GL_MODELVIEW);
729 if (push)
730 glPushMatrix();
731 glLoadIdentity();
736 * Generate a checkerboard texture
738 * \param tex Name of the texture to be used. If \c tex is
739 * zero, a new texture name will be generated.
740 * \param level Mipmap level the checkerboard should be written to
741 * \param width Width of the texture image
742 * \param height Height of the texture image
743 * \param horiz_square_size Size of each checkerboard tile along the X axis
744 * \param vert_square_size Size of each checkerboard tile along the Y axis
745 * \param black RGBA color to be used for "black" tiles
746 * \param white RGBA color to be used for "white" tiles
748 * A texture with alternating black and white squares in a checkerboard
749 * pattern is generated. The texture data is written to LOD \c level of
750 * the texture \c tex.
752 * If \c tex is zero, a new texture created. This texture will have several
753 * texture parameters set to non-default values:
755 * - S and T wrap modes will be set to \c GL_CLAMP_TO_BORDER.
756 * - Border color will be set to { 1.0, 0.0, 0.0, 1.0 }.
757 * - Min and mag filter will be set to \c GL_NEAREST.
759 * \return
760 * Name of the texture. In addition, this texture will be bound to the
761 * \c GL_TEXTURE_2D target of the currently active texture unit.
763 GLuint
764 piglit_checkerboard_texture(GLuint tex, unsigned level,
765 unsigned width, unsigned height,
766 unsigned horiz_square_size,
767 unsigned vert_square_size,
768 const float *black, const float *white)
770 static const GLfloat border_color[4] = { 1.0, 0.0, 0.0, 1.0 };
771 unsigned i;
772 unsigned j;
774 float *const tex_data = malloc(width * height * (4 * sizeof(float)));
775 float *texel = tex_data;
777 for (i = 0; i < height; i++) {
778 const unsigned row = i / vert_square_size;
780 for (j = 0; j < width; j++) {
781 const unsigned col = j / horiz_square_size;
783 if ((row ^ col) & 1) {
784 memcpy(texel, white, 4 * sizeof(float));
785 } else {
786 memcpy(texel, black, 4 * sizeof(float));
789 texel += 4;
794 if (tex == 0) {
795 glGenTextures(1, &tex);
797 glBindTexture(GL_TEXTURE_2D, tex);
798 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
799 GL_NEAREST);
800 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
801 GL_NEAREST);
802 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
803 GL_CLAMP_TO_BORDER);
804 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
805 GL_CLAMP_TO_BORDER);
806 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR,
807 border_color);
808 } else {
809 glBindTexture(GL_TEXTURE_2D, tex);
812 glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0, GL_RGBA,
813 GL_FLOAT, tex_data);
815 return tex;
819 * Generates a texture with the given internalFormat, w, h with a
820 * teximage of r, g, b w quadrants.
822 * Note that for compressed teximages, where the blocking would be
823 * problematic, we assign the whole layers at w == 4 to red, w == 2 to
824 * green, and w == 1 to blue.
826 GLuint
827 piglit_rgbw_texture(GLenum format, int w, int h, GLboolean mip)
829 GLfloat *data;
830 int size, x, y, level;
831 GLuint tex;
832 float red[4] = {1.0, 0.0, 0.0, 1.0};
833 float green[4] = {0.0, 1.0, 0.0, 1.0};
834 float blue[4] = {0.0, 0.0, 1.0, 1.0};
835 float white[4] = {1.0, 1.0, 1.0, 1.0};
837 glGenTextures(1, &tex);
838 glBindTexture(GL_TEXTURE_2D, tex);
839 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
840 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
841 if (mip) {
842 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
843 GL_LINEAR);
844 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
845 GL_LINEAR_MIPMAP_NEAREST);
846 } else {
847 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
848 GL_NEAREST);
849 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
850 GL_NEAREST);
852 data = malloc(w * h * 4 * sizeof(GLfloat));
854 /* XXX: Do we want non-square textures? Surely some day. */
855 assert(w == h);
857 for (level = 0, size = w; size > 0; level++, size >>= 1) {
858 for (y = 0; y < size; y++) {
859 for (x = 0; x < size; x++) {
860 const float *color;
862 if (x < size / 2 && y < size / 2)
863 color = red;
864 else if (y < size / 2)
865 color = green;
866 else if (x < size / 2)
867 color = blue;
868 else
869 color = white;
871 switch (format) {
872 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
873 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
874 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
875 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
876 case GL_COMPRESSED_RGB_FXT1_3DFX:
877 case GL_COMPRESSED_RGBA_FXT1_3DFX:
878 if (size == 4)
879 color = red;
880 else if (size == 2)
881 color = green;
882 else if (size == 1)
883 color = blue;
884 break;
885 default:
886 break;
889 memcpy(data + (y * size + x) * 4, color,
890 4 * sizeof(float));
893 glTexImage2D(GL_TEXTURE_2D, level,
894 format,
895 size, size, 0,
896 GL_RGBA, GL_FLOAT, data);
898 if (!mip)
899 break;
901 free(data);
902 return tex;
905 #ifndef HAVE_STRCHRNUL
906 char *strchrnul(const char *s, int c)
908 char *t = strchr(s, c);
910 return (t == NULL) ? (s + strlen(s)) : t;
912 #endif