ext_transform_feedback: document missing mode in usage
[piglit.git] / tests / general / object-namespace-pollution.c
blobb1857cb0ab74a299cbc8a7dca5578e3706d9a760
1 /*
2 * Copyright © 2015 Intel Corporation
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:
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 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.
24 /**
25 * \file object-namespace-pollution.c
26 * Verify that the GL implementation does not pollute the object namespace.
28 * At least through Mesa 11.1.0, Mesa drivers that use "meta" have some
29 * problems with respect to the OpenGL object namespace. Many places inside
30 * meta allocate objects using a mechanism similar to \c glGen*. This poses
31 * serious problems for applications that create objects without using the
32 * associated \c glGen* function (so called "user generated names").
34 * Section 3.8.12 (Texture Objects) of the OpenGL 2.1 (May 16, 2008) spec
35 * says:
37 * "The command
39 * void GenTextures( sizei n, uint *textures );
41 * returns n previously unused texture object names in textures. These
42 * names are marked as used, for the purposes of GenTextures only, but
43 * they acquire texture state and a dimensionality only when they are
44 * first bound, just as if they were unused."
46 * Calling glBindTexture on an unused name makes that name be used. An
47 * application can mix user generated names and GL generated names only if it
48 * is careful not to reuse names that were previously returned by
49 * glGenTextures. In practice this means that all user generated names must
50 * be used (i.e., bound) before calling glGenTextures.
52 * This effectively means that the GL implementation (or, realistically, GL
53 * middleware) is \b never allowed to use glGenTextures because the
54 * application cannot know what names were returned.
56 * This applies to most kinds of GL objects.
58 * - buffers
59 * - textures
60 * - framebuffers
61 * - renderbuffers
62 * - queries
63 * - vertex programs (from GL_ARB_vertex_program)
64 * - fragment programs (from GL_ARB_fragment_program)
65 * - vertex arrays (from GL_APPLE_vertex_array_object)
66 * - fragment shaders (from GL_ATI_fragment_shader)
68 * Many object types (ARB vertex array objects, transform feedback objects,
69 * program pipeline objects, GLSL shader / program objects, Intel performance
70 * query objects, sampler objects, etc.) forbid user generated names.
72 * Some object types (NVIDIA or APPLE fences, EXT vertex shaders, NVIDIA
73 * transform feedback objects) could probably also suffer from this problem.
74 * However, Mesa does not support these objects, so we don't need to test
75 * them.
77 * GL_AMD_performance_monitor does not specify whether or not user generated
78 * names are allowed.
80 * This test attempts to observe this kind of invalid behavior. First a GL
81 * operation is performed that may need to create an object. Then the test
82 * creates several objects with user generated names. Finally, the GL
83 * operations are performed again. If the GL implemented generated new names
84 * for the purpose of the operations, those names will likely conflict with
85 * one of the user generated names. This should be observable in one of three
86 * ways.
88 * - When the test tries to create the object, the object will already exist.
89 * This is detected by the \c glIs* functions.
91 * - After the second call to the GL operation, the application's object will
92 * have modified state.
94 * - The second call to the GL operation will fail to perform correctly
95 * because the application modified its data.
97 * Only the first two methods are employed by this test. This should catch
98 * the vast majority of possible failures. Verifying the correctness of the
99 * GL operation would add a lot of complexity to the test.
102 #include "piglit-util-gl.h"
104 PIGLIT_GL_TEST_CONFIG_BEGIN
106 config.supports_gl_compat_version = 12;
107 config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_DEPTH | PIGLIT_GL_VISUAL_STENCIL;
108 config.khr_no_error_support = PIGLIT_NO_ERRORS;
110 PIGLIT_GL_TEST_CONFIG_END
112 struct enum_value_pair {
113 GLenum value;
114 GLint expected;
117 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
120 * Spare objects used by test cases.
122 * Some tests need to use objects for the GL operation begin tested. For
123 * example, the \c glGenerateMipmap test needs a texture. These objects
124 * cannot be created using \c glGen* because that would conflict with the rest
125 * of the test. Instead statically allocate object names starting with some
126 * high number that we hope the GL won't use or generate during the test.
128 #define FIRST_SPARE_OBJECT 600
131 * Linear feedback shift register random number generator
133 * Simple Galois LFSRs that is loosely based on
134 * https://en.wikipedia.org/wiki/Linear_feedback_shift_register
136 * The value of \c state is updated to reflect the new state of the LFSR.
137 * This new value should be passed in for the next iteration.
139 * \return
140 * Either 0 or 1 based on the incoming value of \c state.
142 static unsigned
143 lfsr(uint16_t *state)
145 unsigned output = *state & 1;
147 /* For an LFSR, zero is a fixed point, and that's no good for
148 * generating additional values.
150 assert(*state != 0);
152 /* If the output bit is zero, just shift it out. If the output bit is
153 * one, shift it out and toggle some bits.
155 *state = (*state >> 1) ^ (-output & 0x0000B400);
157 return output;
161 * Fill some memory with pseudorandom values
163 * Using two seed values, a pair of LFSRs are used to generate pseudorandom
164 * values to fill the specified memory buffer. Separate invocations with
165 * identical \c bytes, \c seed1, and \c seed2 parameters will generate
166 * identical data. This can be used generate data to initialize a buffer and
167 * regenerate the same data to validate the buffer.
169 static void
170 generate_random_data(void *_output, size_t bytes, uint16_t seed1,
171 uint16_t seed2)
173 uint8_t *output = (uint8_t *) _output;
175 /* If the two seeds are the same, the whole "random" buffer will be
176 * filled with zeroes.
178 assert(seed1 != seed2);
180 for (unsigned i = 0; i < bytes; i++) {
181 uint8_t byte = 0;
183 for (unsigned bit = 0; bit < 8; bit++) {
184 byte <<= 1;
185 byte |= lfsr(&seed1) ^ lfsr(&seed2);
188 output[i] = byte;
192 /** \name Methods for operating on buffer objects */
193 /*@{*/
194 #define BUFFER_DATA_SIZE 1024
196 static bool
197 create_buffer(unsigned name)
199 uint8_t data[BUFFER_DATA_SIZE];
201 if (!piglit_is_extension_supported("GL_ARB_vertex_buffer_object") &&
202 piglit_get_gl_version() < 14) {
203 printf("%s requires vertex buffer objects.\n", __func__);
204 piglit_report_result(PIGLIT_SKIP);
207 generate_random_data(data, sizeof(data), GL_ARRAY_BUFFER, name);
209 if (glIsBuffer(name)) {
210 printf("\t%s,%d: %u is already a buffer\n",
211 __func__, __LINE__, name);
212 return false;
215 glBindBuffer(GL_ARRAY_BUFFER, name);
216 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
217 glBindBuffer(GL_ARRAY_BUFFER, 0);
219 return piglit_check_gl_error(GL_NO_ERROR);
222 static bool
223 validate_buffer(unsigned name)
225 static const struct enum_value_pair test_vectors[] = {
226 { GL_BUFFER_SIZE, BUFFER_DATA_SIZE },
227 { GL_BUFFER_USAGE, GL_STATIC_DRAW },
228 { GL_BUFFER_ACCESS, GL_READ_WRITE },
229 { GL_BUFFER_MAPPED, GL_FALSE },
231 bool pass = true;
232 uint8_t data[BUFFER_DATA_SIZE];
233 void *map;
235 if (!glIsBuffer(name)) {
236 printf("\t%s,%d: %u is not a buffer\n",
237 __func__, __LINE__, name);
238 return false;
241 glBindBuffer(GL_ARRAY_BUFFER, name);
243 for (unsigned i = 0; i < ARRAY_SIZE(test_vectors); i++) {
244 GLint got;
246 glGetBufferParameteriv(GL_ARRAY_BUFFER,
247 test_vectors[i].value,
248 &got);
250 if (got != test_vectors[i].expected) {
251 printf("\t%s,%d: %s of %u: got 0x%x, expected 0x%x\n",
252 __func__, __LINE__,
253 piglit_get_gl_enum_name(test_vectors[i].value),
254 name, got, test_vectors[i].expected);
255 pass = false;
259 generate_random_data(data, sizeof(data), GL_ARRAY_BUFFER, name);
260 map = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
261 if (map != NULL) {
262 if (memcmp(map, data, sizeof(data)) != 0) {
263 printf("\t%s,%d: Data mismatch in %u\n",
264 __func__, __LINE__, name);
265 pass = false;
267 } else {
268 printf("\t%s,%d: Unable to map %u\n",
269 __func__, __LINE__, name);
270 pass = false;
273 glUnmapBuffer(GL_ARRAY_BUFFER);
275 pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
277 return pass;
279 /*@}*/
281 /** \name Methods for operating on framebuffer objects */
282 /*@{*/
283 static bool
284 create_framebuffer(unsigned name)
286 if (!piglit_is_extension_supported("GL_EXT_framebuffer_object")) {
287 printf("%s requires GL_EXT_framebuffer_object.\n", __func__);
288 piglit_report_result(PIGLIT_SKIP);
291 if (glIsFramebufferEXT(name)) {
292 printf("\t%s,%d: %u is already a framebuffer\n",
293 __func__, __LINE__, name);
294 return false;
297 glBindFramebufferEXT(GL_FRAMEBUFFER, name);
298 glBindFramebufferEXT(GL_FRAMEBUFFER, piglit_winsys_fbo);
300 return piglit_check_gl_error(GL_NO_ERROR);
303 static bool
304 validate_framebuffer(unsigned name)
306 static const struct enum_value_pair test_vectors[] = {
307 { GL_COLOR_ATTACHMENT0, 0 },
308 { GL_DEPTH_ATTACHMENT, 0 },
309 { GL_STENCIL_ATTACHMENT, 0 },
311 bool pass = true;
313 if (!glIsFramebufferEXT(name)) {
314 printf("\t%s,%d: %u is not a framebuffer\n",
315 __func__, __LINE__, name);
316 return false;
319 glBindFramebufferEXT(GL_FRAMEBUFFER, name);
321 for (unsigned i = 0; i < ARRAY_SIZE(test_vectors); i++) {
322 GLint got;
324 glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER,
325 test_vectors[i].value,
326 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
327 &got);
329 if (got != test_vectors[i].expected) {
330 printf("\t%s,%d: %s of %u: got 0x%x, expected 0x%x\n",
331 __func__, __LINE__,
332 piglit_get_gl_enum_name(test_vectors[i].value),
333 name, got, test_vectors[i].expected);
334 pass = false;
338 glBindFramebufferEXT(GL_FRAMEBUFFER, piglit_winsys_fbo);
340 return piglit_check_gl_error(GL_NO_ERROR) && pass;
342 /*@}*/
344 /** \name Methods for operating on vertex or fragment program objects */
345 /*@{*/
346 static char *
347 generate_program_source(GLenum target, unsigned key)
349 char *source = NULL;
351 if (target == GL_VERTEX_PROGRAM_ARB) {
352 const char *position;
353 const char *normal;
354 const char *other;
355 const char *mvp;
356 const char *mv_invtrans;
358 if ((key & 2) != 0) {
359 mvp = "state.matrix.mvp";
360 position =
361 "DP4 p.x, mvp[0], vp;\n"
362 "DP4 p.y, mvp[1], vp;\n"
363 "DP4 p.z, mvp[2], vp;\n"
364 "DP4 p.w, mvp[3], vp;\n"
366 } else {
367 mvp = "state.matrix.mvp.transpose";
368 position =
369 "MUL r0, mvp[0], vp.xxxx;\n"
370 "MAD r0, mvp[1], vp.yyyy, r0;\n"
371 "MAD r0, mvp[2], vp.zzzz, r0;\n"
372 "MAD r0, mvp[3], vp.wwww, r0;\n"
373 "MOV p, r0;\n"
377 if ((key & 4) != 0) {
378 mv_invtrans = "state.matrix.modelview.invtrans";
379 normal =
380 "DP3 n.x, mv_invtrans[0], vn;\n"
381 "DP3 n.y, mv_invtrans[1], vn;\n"
382 "DP3 n.z, mv_invtrans[2], vn;\n"
384 } else {
385 mv_invtrans = "state.matrix.modelview.inverse";
386 normal =
387 "MUL r0.xyz, mv_invtrans[0], vn;\n"
388 "MAD r0.xyz, mv_invtrans[1], vn, r0;\n"
389 "MAD r0.xyz, mv_invtrans[2], vn, r0;\n"
390 "SWZ n, r0, x, y, z, 0;\n"
394 if ((key & 8) != 0) {
395 other =
396 "# Output the color\n"
397 "MOV t, vertex.color;\n"
399 } else {
400 other =
401 "# Output the texture coordinate\n"
402 "MOV t, vertex.texcoord[0];\n"
406 (void)!asprintf(&source,
407 "!!ARBvp1.0\n"
408 "# Program key 0x%04x\n"
409 "ATTRIB vp = vertex.position;\n"
410 "ATTRIB vn = vertex.normal;\n"
411 "PARAM mvp[4] = { %s.row[0..3] };\n"
412 "PARAM mv_invtrans[3] = { %s.row[0..2] };\n"
413 "OUTPUT p = result.position;\n"
414 "OUTPUT n = result.texcoord[0];\n"
415 "OUTPUT t = result.texcoord[1];\n"
416 "TEMP r0;\n"
417 "\n"
418 "# Transform the vertex to clip coordinates.\n"
419 "%s"
420 "\n"
421 "# Transform the normal to eye coordinates.\n"
422 "%s"
423 "\n"
424 "%s"
425 "END",
426 key,
427 mvp,
428 mv_invtrans,
429 position,
430 normal,
431 other);
432 } else if (target == GL_FRAGMENT_PROGRAM_ARB) {
433 const char *tex;
434 const char *half_dir;
435 const char *light_dir;
437 if ((key & 2) != 0) {
438 tex = "TEX r0, t, texture[0], 2D;";
439 } else {
440 tex = "TEX r0, t, texture[0], 1D;";
443 if ((key & 4) != 0) {
444 light_dir = "program.env[0]";
445 } else {
446 light_dir = "state.light[0].position";
449 if ((key & 4) != 0) {
450 half_dir = "program.env[1]";
451 } else {
452 half_dir = "state.light[0].half";
455 (void)!asprintf(&source,
456 "!!ARBfp1.0\n"
457 "# Program key 0x%04x\n"
458 "ATTRIB n = fragment.texcoord[0];\n"
459 "ATTRIB t = fragment.texcoord[1];\n"
460 "PARAM light_dir = %s;\n"
461 "PARAM half_dir = %s;\n"
462 "OUTPUT c = result.color;\n"
463 "TEMP r0, r1;\n"
464 "\n"
465 "# Sample the texture\n"
466 "%s"
467 "\n"
468 "# Compute lighting\n"
469 "DP3 r1.x, n, light_dir;\n"
470 "DP3 r1.y, n, half_dir;\n"
471 "MOV r1.w, 126.2;\n"
472 "LIT r1, r1;\n"
473 "\n"
474 "# Combine lighting and texture\n"
475 "MUL r0, r1.y, r0;\n"
476 "ADD c.xyz, r1.z, r0;\n"
477 "MOV c.w, 1.0;\n"
478 "END",
479 key,
480 light_dir,
481 half_dir,
482 tex);
483 } else {
484 printf("Unknown program target %s (0x%04x) in %s.\n",
485 piglit_get_gl_enum_name(target), target,
486 __func__);
487 piglit_report_result(PIGLIT_FAIL);
490 return source;
494 * Selects a program target based on the key and the supported extensions.
496 static GLenum
497 select_program_target(unsigned key)
499 GLenum target = 0;
501 if (piglit_is_extension_supported("GL_ARB_vertex_program")) {
502 target = GL_VERTEX_PROGRAM_ARB;
505 if (piglit_is_extension_supported("GL_ARB_fragment_program")) {
506 if (target == 0 || (key & 1) == 0)
507 target = GL_FRAGMENT_PROGRAM_ARB;
510 return target;
513 static bool
514 create_program(unsigned name)
516 char *source;
517 const GLenum target = select_program_target(name);
519 if (target == 0) {
520 printf("%s requires GL_ARB_vertex_program or "
521 "GL_ARB_fragment_program.\n",
522 __func__);
523 piglit_report_result(PIGLIT_SKIP);
526 if (glIsProgramARB(name)) {
527 printf("\t%s,%d: %u is already a program\n",
528 __func__, __LINE__, name);
529 return false;
532 glBindProgramARB(target, name);
534 source = generate_program_source(target, name);
535 glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB,
536 strlen(source), source);
538 free(source);
540 glBindProgramARB(target, 0);
542 return piglit_check_gl_error(GL_NO_ERROR);
545 static bool
546 validate_program(unsigned name)
548 bool pass = true;
549 const GLenum target = select_program_target(name);
550 char *expected = generate_program_source(target, name);
551 const int expected_length = strlen(expected);
552 char *got;
553 GLint length;
555 if (!glIsProgramARB(name)) {
556 printf("\t%s,%d: %u is not a program\n",
557 __func__, __LINE__, name);
558 free(expected);
559 return false;
562 glBindProgramARB(target, name);
564 /* The GL_ARB_vertex_program spec does not say whether or not length
565 * includes a terminating NUL. It says:
567 * "If <pname> is PROGRAM_LENGTH_ARB ... GetProgramivARB returns
568 * one integer holding the program string length (in bytes)
569 * ... for the program object currently bound to <target>."
571 * and, with respect to glGetProgramStringARB it says:
573 * "<n> ubytes are returned into the array program where <n> is
574 * the length of the program in ubytes, as returned by
575 * GetProgramivARB when <pname> is PROGRAM_LENGTH_ARB."
577 glGetProgramivARB(target,
578 GL_PROGRAM_LENGTH_ARB,
579 &length);
580 if (length != expected_length && length != (expected_length + 1)) {
581 printf("\t%s,%d: Program %u length invalid: got %d, expected "
582 "%d or %d.\n",
583 __func__, __LINE__,
584 name,
585 length, expected_length, expected_length + 1);
586 pass = false;
589 got = calloc(length, sizeof(char));
590 glGetProgramStringARB(target,
591 GL_PROGRAM_STRING_ARB,
592 got);
594 if (memcmp(expected, got, expected_length) != 0) {
595 printf("\t%s,%d: %u source mismatch\n",
596 __func__, __LINE__,
597 name);
598 pass = false;
601 free(got);
602 free(expected);
604 glBindProgramARB(target, 0);
606 return piglit_check_gl_error(GL_NO_ERROR) && pass;
608 /*@}*/
610 /** \name Methods for operating on renderbuffer objects */
611 /*@{*/
612 static bool
613 create_renderbuffer(unsigned name)
615 if (!piglit_is_extension_supported("GL_EXT_framebuffer_object")) {
616 printf("%s requires GL_EXT_framebuffer_object.\n", __func__);
617 piglit_report_result(PIGLIT_SKIP);
620 if (glIsRenderbufferEXT(name)) {
621 printf("\t%s,%d: %u is already a renderbuffer\n",
622 __func__, __LINE__, name);
623 return false;
626 glBindRenderbufferEXT(GL_RENDERBUFFER, name);
627 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA8,
628 17 /* width */, 15 /* height */);
630 glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
632 return piglit_check_gl_error(GL_NO_ERROR);
635 static bool
636 validate_renderbuffer(unsigned name)
638 static const struct enum_value_pair test_vectors[] = {
639 { GL_RENDERBUFFER_WIDTH, 17 },
640 { GL_RENDERBUFFER_HEIGHT, 15 },
641 { GL_RENDERBUFFER_INTERNAL_FORMAT, GL_RGBA8 },
642 { GL_RENDERBUFFER_DEPTH_SIZE, 0 },
643 { GL_RENDERBUFFER_STENCIL_SIZE, 0 },
645 bool pass = true;
647 if (!glIsRenderbufferEXT(name)) {
648 printf("\t%s,%d: %u is not a renderbuffer\n",
649 __func__, __LINE__, name);
650 return false;
653 glBindRenderbufferEXT(GL_RENDERBUFFER, name);
655 for (unsigned i = 0; i < ARRAY_SIZE(test_vectors); i++) {
656 GLint got;
658 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER,
659 test_vectors[i].value,
660 &got);
662 if (got != test_vectors[i].expected) {
663 printf("\t%s,%d: %s of %u: got 0x%x, expected 0x%x\n",
664 __func__, __LINE__,
665 piglit_get_gl_enum_name(test_vectors[i].value),
666 name, got, test_vectors[i].expected);
667 pass = false;
671 glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
673 return piglit_check_gl_error(GL_NO_ERROR) && pass;
675 /*@}*/
677 /** \name Methods for operating on texture objects */
678 /*@{*/
679 #define TEXTURE_DATA_SIZE (16 * 16 * sizeof(GLuint))
681 static bool
682 create_texture(unsigned name)
684 uint8_t data[TEXTURE_DATA_SIZE];
686 generate_random_data(data, sizeof(data), GL_TEXTURE_2D, name);
688 if (glIsTexture(name)) {
689 printf("\t%s,%d: %u is already a texture\n",
690 __func__, __LINE__, name);
691 return false;
694 glBindTexture(GL_TEXTURE_2D, name);
695 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_RGBA,
696 GL_UNSIGNED_INT_8_8_8_8, data);
697 glBindTexture(GL_TEXTURE_2D, 0);
699 return piglit_check_gl_error(GL_NO_ERROR);
702 static bool
703 validate_texture(unsigned name)
705 static const struct enum_value_pair tex_test_vectors[] = {
706 { GL_TEXTURE_WRAP_S, GL_REPEAT },
707 { GL_TEXTURE_WRAP_T, GL_REPEAT },
708 { GL_TEXTURE_WRAP_R, GL_REPEAT },
709 { GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR },
710 { GL_TEXTURE_MAG_FILTER, GL_LINEAR },
711 { GL_TEXTURE_BASE_LEVEL, 0 },
712 { GL_TEXTURE_MAX_LEVEL, 1000 },
714 static const struct enum_value_pair tex_level_test_vectors[] = {
715 { GL_TEXTURE_WIDTH, 16 },
716 { GL_TEXTURE_HEIGHT, 16 },
717 { GL_TEXTURE_INTERNAL_FORMAT, GL_RGBA8 },
719 bool pass = true;
720 uint8_t data[TEXTURE_DATA_SIZE];
721 uint8_t texels[TEXTURE_DATA_SIZE];
723 if (!glIsTexture(name)) {
724 printf("\t%s,%d: %u is not a texture\n",
725 __func__, __LINE__, name);
726 return false;
729 glBindTexture(GL_TEXTURE_2D, name);
731 for (unsigned i = 0; i < ARRAY_SIZE(tex_test_vectors); i++) {
732 GLint got;
734 glGetTexParameteriv(GL_TEXTURE_2D,
735 tex_test_vectors[i].value,
736 &got);
738 if (got != tex_test_vectors[i].expected) {
739 printf("\t%s,%d: %s of %u: got 0x%x, expected 0x%x\n",
740 __func__, __LINE__,
741 piglit_get_gl_enum_name(tex_test_vectors[i].value),
742 name, got, tex_test_vectors[i].expected);
743 pass = false;
747 for (unsigned i = 0; i < ARRAY_SIZE(tex_level_test_vectors); i++) {
748 GLint got;
750 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
751 tex_level_test_vectors[i].value,
752 &got);
754 if (got != tex_level_test_vectors[i].expected) {
755 printf("\t%s,%d: %s of %u: got 0x%x, expected 0x%x\n",
756 __func__, __LINE__,
757 piglit_get_gl_enum_name(tex_level_test_vectors[i].value),
758 name, got, tex_level_test_vectors[i].expected);
759 pass = false;
763 /* Try to use glGetnTexImageARB. If the test's 16x16 texture was
764 * replaced with something larger, the call to glGetTexImage will
765 * probably segfault. This could be worked around, but it doesn't
766 * seem worth it.
768 * If the texture size did change, the glGetTexLevelParameteriv loop
769 * above will have already detected it.
771 generate_random_data(data, sizeof(data), GL_TEXTURE_2D, name);
772 if (piglit_is_extension_supported("GL_ARB_robustness")) {
773 /* Note: if sizeof(texels) is less than the size of the image,
774 * glGetnTexImageARB will generate GL_INVALID_OPERATION.
776 glGetnTexImageARB(GL_TEXTURE_2D, 0, GL_RGBA,
777 GL_UNSIGNED_INT_8_8_8_8,
778 sizeof(texels), texels);
779 } else {
780 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA,
781 GL_UNSIGNED_INT_8_8_8_8,
782 texels);
785 if (memcmp(texels, data, sizeof(data)) != 0) {
786 printf("\t%s,%d: Data mismatch in %u\n",
787 __func__, __LINE__, name);
788 pass = false;
791 glBindTexture(GL_TEXTURE_2D, 0);
793 return piglit_check_gl_error(GL_NO_ERROR) && pass;
795 /*@}*/
797 /** \name Methods for operating on Apple vertex array objects */
798 /*@{*/
799 static float dummy_vao_data[257];
801 static const int vao_vertex_size[] = { 2, 3, 4 };
802 static const int vao_color_size[] = { 3, 4 };
803 static const int vao_texture_size[] = { 1, 2, 3, 4 };
804 static const GLenum vao_vertex_type[] = { GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE };
805 static const GLenum vao_normal_type[] = { GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE };
806 static const GLenum vao_color_type[] = {
807 GL_BYTE, GL_UNSIGNED_BYTE,
808 GL_SHORT, GL_UNSIGNED_SHORT,
809 GL_INT, GL_UNSIGNED_INT,
810 GL_FLOAT,
811 GL_DOUBLE
814 #define PICK(a, i) a[i % ARRAY_SIZE(a)]
815 #define STRIDE(x) (((x) % 16) * sizeof(int))
817 /* 4 arrays, and each has at most 4 values. */
818 #define VAO_DATA_SIZE (4 * 4)
820 static bool
821 create_vertex_array(unsigned name)
823 uint8_t data[VAO_DATA_SIZE];
825 if (!piglit_is_extension_supported("GL_APPLE_vertex_array_object")) {
826 printf("%s requires GL_APPLE_vertex_array_object.\n", __func__);
827 piglit_report_result(PIGLIT_SKIP);
830 if (glIsVertexArrayAPPLE(name)) {
831 printf("\t%s,%d: %u is already a vertex array\n",
832 __func__, __LINE__, name);
833 return false;
836 glBindVertexArrayAPPLE(name);
838 generate_random_data(data,
839 sizeof(data),
840 GL_VERTEX_ARRAY_BINDING_APPLE,
841 name);
843 glVertexPointer(PICK(vao_vertex_size, data[0]),
844 PICK(vao_vertex_type, data[1]),
845 STRIDE(data[2]),
846 &dummy_vao_data[data[3]]);
847 glNormalPointer(PICK(vao_normal_type, data[4]),
848 STRIDE(data[5]),
849 &dummy_vao_data[data[6]]);
850 glColorPointer(PICK(vao_color_size, data[7]),
851 PICK(vao_color_type, data[8]),
852 STRIDE(data[9]),
853 &dummy_vao_data[data[10]]);
854 glTexCoordPointer(PICK(vao_texture_size, data[11]),
855 PICK(vao_vertex_type, data[12]),
856 STRIDE(data[13]),
857 &dummy_vao_data[data[14]]);
859 glBindVertexArrayAPPLE(0);
861 return piglit_check_gl_error(GL_NO_ERROR);
864 static bool
865 check_integer_query(GLenum pname, int expected, unsigned name,
866 const char *caller)
868 int got;
870 glGetIntegerv(pname, &got);
871 if (got != expected) {
872 printf("\t%s,%d: %s of %u: got 0x%x, expected 0x%x\n",
873 caller, __LINE__,
874 piglit_get_gl_enum_name(pname),
875 name,
876 got, expected);
877 return false;
880 return true;
883 static bool
884 check_pointer_query(GLenum pname, const void *expected, unsigned name,
885 const char *caller)
887 void *got;
889 glGetPointerv(pname, &got);
890 if (got != expected) {
891 printf("\t%s,%d: %s of %u: got %p, expected %p\n",
892 caller, __LINE__,
893 piglit_get_gl_enum_name(pname),
894 name,
895 got, expected);
896 return false;
899 return true;
902 static bool
903 validate_vertex_array(unsigned name)
905 uint8_t data[VAO_DATA_SIZE];
906 bool pass = true;
908 if (!piglit_is_extension_supported("GL_APPLE_vertex_array_object"))
909 return true;
911 if (!glIsVertexArrayAPPLE(name)) {
912 printf("\t%s,%d: %u is not a vertex array\n",
913 __func__, __LINE__, name);
914 return false;
917 glBindVertexArrayAPPLE(name);
919 generate_random_data(data,
920 sizeof(data),
921 GL_VERTEX_ARRAY_BINDING_APPLE,
922 name);
924 pass = check_integer_query(GL_VERTEX_ARRAY_SIZE,
925 PICK(vao_vertex_size, data[0]),
926 name,
927 __func__) && pass;
928 pass = check_integer_query(GL_VERTEX_ARRAY_TYPE,
929 PICK(vao_vertex_type, data[1]),
930 name,
931 __func__) && pass;
932 pass = check_integer_query(GL_VERTEX_ARRAY_STRIDE,
933 STRIDE(data[2]),
934 name,
935 __func__) && pass;
936 pass = check_pointer_query(GL_VERTEX_ARRAY_POINTER,
937 &dummy_vao_data[data[3]],
938 name,
939 __func__) && pass;
941 pass = check_integer_query(GL_NORMAL_ARRAY_TYPE,
942 PICK(vao_normal_type, data[4]),
943 name,
944 __func__) && pass;
945 pass = check_integer_query(GL_NORMAL_ARRAY_STRIDE,
946 STRIDE(data[5]),
947 name,
948 __func__) && pass;
949 pass = check_pointer_query(GL_NORMAL_ARRAY_POINTER,
950 &dummy_vao_data[data[6]],
951 name,
952 __func__) && pass;
954 pass = check_integer_query(GL_COLOR_ARRAY_SIZE,
955 PICK(vao_color_size, data[7]),
956 name,
957 __func__) && pass;
958 pass = check_integer_query(GL_COLOR_ARRAY_TYPE,
959 PICK(vao_color_type, data[8]),
960 name,
961 __func__) && pass;
962 pass = check_integer_query(GL_COLOR_ARRAY_STRIDE,
963 STRIDE(data[9]),
964 name,
965 __func__) && pass;
966 pass = check_pointer_query(GL_COLOR_ARRAY_POINTER,
967 &dummy_vao_data[data[10]],
968 name,
969 __func__) && pass;
971 pass = check_integer_query(GL_TEXTURE_COORD_ARRAY_SIZE,
972 PICK(vao_texture_size, data[11]),
973 name,
974 __func__) && pass;
975 pass = check_integer_query(GL_TEXTURE_COORD_ARRAY_TYPE,
976 PICK(vao_vertex_type, data[12]),
977 name,
978 __func__) && pass;
979 pass = check_integer_query(GL_TEXTURE_COORD_ARRAY_STRIDE,
980 STRIDE(data[13]),
981 name,
982 __func__) && pass;
983 pass = check_pointer_query(GL_TEXTURE_COORD_ARRAY_POINTER,
984 &dummy_vao_data[data[14]],
985 name,
986 __func__) && pass;
988 glBindVertexArrayAPPLE(0);
989 return piglit_check_gl_error(GL_NO_ERROR) && pass;
991 /*@}*/
993 /** \name GL operation wrapper functions. */
994 /*@{*/
995 static bool
996 do_Bitmap(void)
998 GLint old_unpack_alignment;
999 uint8_t bitmap[16 * 16 / 8];
1001 glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_unpack_alignment);
1002 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1003 /* Enable depth test to avoid i965 blit path. */
1004 glEnable(GL_DEPTH_TEST);
1006 memset(bitmap, 0xff, sizeof(bitmap));
1007 glBitmap(16, 16, 0, 0, 0, 0, bitmap);
1009 glDisable(GL_DEPTH_TEST);
1010 glPixelStorei(GL_UNPACK_ALIGNMENT, old_unpack_alignment);
1012 return piglit_check_gl_error(GL_NO_ERROR);
1015 static bool
1016 do_BlitFramebuffer(void)
1018 const GLuint fbos[2] = { FIRST_SPARE_OBJECT, FIRST_SPARE_OBJECT + 1 };
1019 const GLuint tex[2] = { FIRST_SPARE_OBJECT, FIRST_SPARE_OBJECT + 1 };
1020 bool pass = true;
1022 /* GL_ARB_framebuffer_object and OpenGL 3.0 require that
1023 * glGenFramebuffers be used. This test really does require
1024 * GL_EXT_framebuffer_object and GL_EXT_framebuffer_blit.
1026 if (!(piglit_is_extension_supported("GL_EXT_framebuffer_object") &&
1027 piglit_is_extension_supported("GL_EXT_framebuffer_blit"))) {
1028 printf("%s requires EXT framebuffer objects.\n", __func__);
1029 piglit_report_result(PIGLIT_SKIP);
1032 /* Generate the texture objects that will be attached to the
1033 * framebuffer objects for the test.
1035 glBindTexture(GL_TEXTURE_2D, tex[0]);
1036 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_RGBA,
1037 GL_UNSIGNED_BYTE, NULL);
1039 glBindTexture(GL_TEXTURE_2D, tex[1]);
1040 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_RGBA,
1041 GL_UNSIGNED_BYTE, NULL);
1043 glBindTexture(GL_TEXTURE_2D, 0);
1045 /* Generate the framebuffer objects. */
1046 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, fbos[0]);
1047 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1048 GL_TEXTURE_2D, tex[0], 0 /* level */);
1049 if (glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER) !=
1050 GL_FRAMEBUFFER_COMPLETE) {
1051 printf("\t%s,%d: Draw framebuffer is not complete.\n",
1052 __func__, __LINE__);
1053 pass = false;
1056 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbos[1]);
1057 glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1058 GL_TEXTURE_2D, tex[1], 0 /* level */);
1059 if (glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER) !=
1060 GL_FRAMEBUFFER_COMPLETE) {
1061 printf("\t%s,%d: Read framebuffer is not complete.\n",
1062 __func__, __LINE__);
1063 pass = false;
1066 /* Do the "real" test. */
1067 glBlitFramebufferEXT(0 /* srcX0 */, 0 /* srcY0 */,
1068 8 /* srcX1 */, 8 /* srcY1 */,
1069 0 /* dstX0 */, 0 /* dstY0 */,
1070 8 /* dstX1 */, 8 /* dstY1 */,
1071 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1073 /* Final clean up. */
1074 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, piglit_winsys_fbo);
1075 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo);
1077 glDeleteTextures(ARRAY_SIZE(tex), tex);
1078 glDeleteFramebuffersEXT(ARRAY_SIZE(fbos), fbos);
1080 return piglit_check_gl_error(GL_NO_ERROR) && pass;
1083 static bool
1084 do_Clear(void)
1086 /* Pick a clear value that should avoid common hardware "fast clear"
1087 * optimizations.
1089 glClearColor(0.5, 0.7, 0.8, 0.2);
1091 glClear(GL_COLOR_BUFFER_BIT);
1093 glClearColor(0.0, 0.0, 0.0, 0.0);
1094 return piglit_check_gl_error(GL_NO_ERROR);
1097 static bool
1098 do_ClearTexSubImage(void)
1100 GLuint tex = FIRST_SPARE_OBJECT;
1102 /* Pick a clear value that should avoid common hardware "fast clear"
1103 * optimizations.
1105 const GLuint clear_data = 0xDEADBEEF;
1107 if (!piglit_is_extension_supported("GL_ARB_clear_texture")) {
1108 printf("%s requires GL_ARB_clear_texture.\n", __func__);
1109 piglit_report_result(PIGLIT_SKIP);
1112 glBindTexture(GL_TEXTURE_2D, tex);
1113 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_RGBA,
1114 GL_UNSIGNED_INT_8_8_8_8, NULL);
1115 glBindTexture(GL_TEXTURE_2D, 0);
1117 glClearTexSubImage(tex, 0 /* level */,
1118 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */,
1119 16 /* width */, 16 /* height */, 1 /* depth */,
1120 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
1121 &clear_data);
1123 glDeleteTextures(1, &tex);
1125 return piglit_check_gl_error(GL_NO_ERROR);
1128 static bool
1129 do_CopyImageSubData(void)
1131 const GLuint tex[2] = { FIRST_SPARE_OBJECT, FIRST_SPARE_OBJECT + 1 };
1133 if (!piglit_is_extension_supported("GL_ARB_copy_image")) {
1134 printf("%s requires GL_ARB_copy_image.\n", __func__);
1135 piglit_report_result(PIGLIT_SKIP);
1138 glBindTexture(GL_TEXTURE_2D, tex[0]);
1139 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0,
1140 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1141 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1143 glBindTexture(GL_TEXTURE_2D, tex[1]);
1144 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0,
1145 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1146 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1148 glBindTexture(GL_TEXTURE_2D, 0);
1150 glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0 /* srcLevel */,
1151 0 /* srcX */, 0 /* srcY */, 0 /* srcZ */,
1152 tex[1], GL_TEXTURE_2D, 0 /* dstLevel */,
1153 0 /* dstX */, 0 /* dstY */, 0 /* dstZ */,
1154 16 /* srcWidth */, 16 /* srcHeight */,
1155 1 /* srcDepth */);
1157 glDeleteTextures(ARRAY_SIZE(tex), tex);
1159 return piglit_check_gl_error(GL_NO_ERROR);
1162 static bool
1163 do_CopyPixels(void)
1165 /* Set non-1.0 pixel zoom to avoid i965 blit path. */
1166 glPixelZoom(1.5f, 1.5f);
1168 glRasterPos2f(0.5, 0.5);
1169 glCopyPixels(0, 0, 4, 4, GL_COLOR);
1171 glPixelZoom(1.0f, 1.0f);
1173 return piglit_check_gl_error(GL_NO_ERROR);
1176 static bool
1177 do_CopyTexSubImage2D(void)
1179 GLuint tex = FIRST_SPARE_OBJECT;
1181 /* Set non-1.0 pixel zoom to avoid i965 blorp path. */
1182 glPixelZoom(1.5f, 1.5f);
1184 glBindTexture(GL_TEXTURE_2D, tex);
1186 /* Pick GL_LUMINANCE8_ALPHA8 because most hardware can support it
1187 * natively, and most hardware cannot use a blit fast path from RGB or
1188 * RGBA to LA. i965 currently cannot.
1190 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE8_ALPHA8, 16, 16, 0,
1191 GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
1193 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 16, 16);
1195 glPixelZoom(1.0f, 1.0f);
1197 glBindTexture(GL_TEXTURE_2D, 0);
1198 glDeleteTextures(1, &tex);
1200 return piglit_check_gl_error(GL_NO_ERROR);
1203 static bool
1204 do_DrawPixels(void)
1206 GLuint pixels[16 * 16];
1208 memset(pixels, 0x81, sizeof(pixels));
1209 glDrawPixels(16, 16, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, pixels);
1210 glDrawPixels(16, 16, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, pixels);
1211 glDrawPixels(16, 16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, pixels);
1213 return piglit_check_gl_error(GL_NO_ERROR);
1216 static bool
1217 do_GenerateMipmap(void)
1219 const GLuint tex = FIRST_SPARE_OBJECT;
1220 bool pass = true;
1222 if (!piglit_is_extension_supported("GL_EXT_framebuffer_object") &&
1223 !piglit_is_extension_supported("GL_ARB_framebuffer_object") &&
1224 piglit_get_gl_version() < 30) {
1225 printf("%s requires framebuffer objects.\n", __func__);
1226 piglit_report_result(PIGLIT_SKIP);
1229 if (glIsTexture(tex)) {
1230 printf("\t%s,%d: %u is already a texture\n",
1231 __func__, __LINE__, tex);
1232 pass = false;
1235 glBindTexture(GL_TEXTURE_2D, tex);
1236 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_RGBA,
1237 GL_UNSIGNED_INT_8_8_8_8, NULL);
1238 glGenerateMipmap(GL_TEXTURE_2D);
1240 glBindTexture(GL_TEXTURE_2D, 0);
1241 glDeleteTextures(1, &tex);
1243 return piglit_check_gl_error(GL_NO_ERROR) && pass;
1246 static bool
1247 do_GetTexImage(void)
1249 const GLuint tex = FIRST_SPARE_OBJECT;
1250 const GLuint pbo = FIRST_SPARE_OBJECT;
1251 uint8_t data[TEXTURE_DATA_SIZE];
1252 bool pass = true;
1254 if (!piglit_is_extension_supported("GL_EXT_pixel_buffer_object") &&
1255 piglit_get_gl_version() < 30) {
1256 printf("%s requires pixel buffer objects.\n", __func__);
1257 piglit_report_result(PIGLIT_SKIP);
1260 if (glIsTexture(tex)) {
1261 printf("\t%s,%d: %u is already a texture\n",
1262 __func__, __LINE__, tex);
1263 pass = false;
1266 if (glIsBuffer(pbo)) {
1267 printf("\t%s,%d: %u is already a buffer object\n",
1268 __func__, __LINE__, pbo);
1269 pass = false;
1272 /* Generate the initial texture object. The random number seed values
1273 * used are irrelevant.
1275 generate_random_data(data, sizeof(data), GL_PIXEL_UNPACK_BUFFER, pbo);
1276 glBindTexture(GL_TEXTURE_2D, tex);
1277 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_RGBA,
1278 GL_UNSIGNED_BYTE, data);
1281 /* Generate the buffer object that will be used for the PBO download
1282 * from the texture.
1284 glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
1285 glBufferData(GL_PIXEL_PACK_BUFFER, sizeof(data), NULL, GL_STATIC_READ);
1287 /* Do the "real" test. */
1288 glGetTexImage(GL_TEXTURE_2D, 0 /* level */,
1289 GL_RGBA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
1291 /* Final clean up. */
1292 glBindTexture(GL_TEXTURE_2D, 0);
1293 glDeleteTextures(1, &tex);
1295 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
1296 glDeleteBuffers(1, &pbo);
1298 return piglit_check_gl_error(GL_NO_ERROR) && pass;
1301 static bool
1302 do_GetTexImage_compressed(void)
1304 const GLuint tex = FIRST_SPARE_OBJECT;
1305 const GLenum internal_format =
1306 piglit_is_extension_supported("GL_EXT_texture_compression_s3tc")
1307 ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
1308 : GL_COMPRESSED_RGBA_FXT1_3DFX;
1310 /* DXT1 has 4x4 block size. The image will be 16x16 texels,
1311 * so that means 16 blocks. Each block is 64-bits (or 8
1312 * bytes). That's a total of 16 * 8 = 128 bytes.
1314 * FXT1 has 8x4 block size. The image will be 16x16 texels,
1315 * so that means 8 blocks. Each block is 128-bits (or 16
1316 * bytes). That's a total of 8 * 16 = 128 bytes.
1318 uint8_t data[128];
1320 /* Buffer to hold the decompressed texture. */
1321 uint8_t texels[16 * 16 * 4];
1323 bool pass = true;
1325 /* This test requires:
1327 * GL_EXT_texture_compression_s3tc or GL_3DFX_texture_compression_FXT1
1329 * and
1331 * GL_ARB_texture_compression or OpenGL 1.3
1333 if (!(piglit_is_extension_supported("GL_ARB_texture_compression") ||
1334 piglit_get_gl_version() >= 13) ||
1335 !(piglit_is_extension_supported("GL_EXT_texture_compression_s3tc") ||
1336 piglit_is_extension_supported("GL_3DFX_texture_compression_FXT1"))) {
1337 printf("%s requires either S3TC or FXT1 texture compression.\n",
1338 __func__);
1339 piglit_report_result(PIGLIT_SKIP);
1342 if (glIsTexture(tex)) {
1343 printf("\t%s,%d: %u is already a texture\n",
1344 __func__, __LINE__, tex);
1345 pass = false;
1348 /* Generate the initial texture object. The random number seed values
1349 * used are irrelevant.
1351 generate_random_data(data, sizeof(data), GL_PIXEL_UNPACK_BUFFER, tex);
1352 glBindTexture(GL_TEXTURE_2D, tex);
1353 glCompressedTexImage2D(GL_TEXTURE_2D, 0 /* level */, internal_format,
1354 16 /* width */, 16 /* height */, 0 /* border */,
1355 sizeof(data), data);
1357 /* Do the "real" test. */
1358 glGetTexImage(GL_TEXTURE_2D, 0 /* level */,
1359 GL_RGBA, GL_UNSIGNED_BYTE, texels);
1361 /* Final clean up. */
1362 glBindTexture(GL_TEXTURE_2D, 0);
1363 glDeleteTextures(1, &tex);
1365 return piglit_check_gl_error(GL_NO_ERROR) && pass;
1368 static bool
1369 do_TexSubImage2D(void)
1371 const GLuint tex = FIRST_SPARE_OBJECT;
1372 const GLuint pbo = FIRST_SPARE_OBJECT;
1373 uint8_t data[TEXTURE_DATA_SIZE];
1374 bool pass = true;
1376 if (!piglit_is_extension_supported("GL_EXT_pixel_buffer_object") &&
1377 piglit_get_gl_version() < 30) {
1378 printf("%s requires pixel buffer objects.\n", __func__);
1379 piglit_report_result(PIGLIT_SKIP);
1382 if (glIsTexture(tex)) {
1383 printf("\t%s,%d: %u is already a texture\n",
1384 __func__, __LINE__, tex);
1385 pass = false;
1388 if (glIsBuffer(pbo)) {
1389 printf("\t%s,%d: %u is already a buffer object\n",
1390 __func__, __LINE__, pbo);
1391 pass = false;
1394 /* Generate the initial texture object.
1396 * NOTE: This must occur before binding the PBO. Otherwise
1397 * the NULL texel pointer will be interpreted as a zero offset
1398 * in the buffer, and glTexImage2D will upload data from the
1399 * PBO. This is not the intent of this test.
1401 glBindTexture(GL_TEXTURE_2D, tex);
1402 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_RGBA,
1403 GL_UNSIGNED_INT_8_8_8_8, NULL);
1406 /* Generate the buffer object that will be used for the PBO upload
1407 * to the texture.
1409 generate_random_data(data, sizeof(data), GL_PIXEL_UNPACK_BUFFER, pbo);
1411 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
1412 glBufferData(GL_PIXEL_UNPACK_BUFFER, sizeof(data), data,
1413 GL_STATIC_DRAW);
1415 /* Do the "real" test. */
1416 glTexSubImage2D(GL_TEXTURE_2D, 0 /* level */,
1417 0 /* xoffset */, 0 /* yoffset */,
1418 16 /* width */, 16 /* height */,
1419 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, BUFFER_OFFSET(0));
1421 /* Final clean up. */
1422 glBindTexture(GL_TEXTURE_2D, 0);
1423 glDeleteTextures(1, &tex);
1425 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1426 glDeleteBuffers(1, &pbo);
1428 return piglit_check_gl_error(GL_NO_ERROR) && pass;
1430 /*@}*/
1432 static const struct operation {
1433 const char *name;
1434 bool (*func)(void);
1435 } operation_table[] = {
1436 { "glBitmap", do_Bitmap },
1437 { "glBlitFramebuffer", do_BlitFramebuffer },
1438 { "glClear", do_Clear },
1439 { "glClearTexSubImage", do_ClearTexSubImage },
1440 { "glCopyImageSubData", do_CopyImageSubData },
1441 { "glCopyPixels", do_CopyPixels },
1442 { "glCopyTexSubImage2D", do_CopyTexSubImage2D },
1443 { "glDrawPixels", do_DrawPixels },
1444 { "glGenerateMipmap", do_GenerateMipmap },
1445 { "glGetTexImage", do_GetTexImage },
1446 { "glGetTexImage-compressed", do_GetTexImage_compressed },
1447 { "glTexSubImage2D", do_TexSubImage2D },
1450 static const struct object_type {
1451 const char *name;
1452 bool (*create)(unsigned name);
1453 bool (*validate)(unsigned name);
1454 } object_type_table[] = {
1455 { "buffer", create_buffer, validate_buffer },
1456 { "framebuffer", create_framebuffer, validate_framebuffer },
1457 { "program", create_program, validate_program },
1458 { "renderbuffer", create_renderbuffer, validate_renderbuffer },
1459 { "texture", create_texture, validate_texture },
1460 { "vertex-array", create_vertex_array, validate_vertex_array },
1463 static NORETURN void
1464 usage(const char *prog)
1466 unsigned i;
1468 printf("Usage:\n");
1469 printf("\t%s operation object-type\n\n", prog);
1470 printf("Where operation is one of:\n");
1472 for (i = 0; i < ARRAY_SIZE(operation_table); i++)
1473 printf("\t%s\n", operation_table[i].name);
1475 printf("\nAnd object-type is one of:\n");
1477 for (i = 0; i < ARRAY_SIZE(object_type_table); i++)
1478 printf("\t%s\n", object_type_table[i].name);
1480 piglit_report_result(PIGLIT_FAIL);
1483 void
1484 piglit_init(int argc, char **argv)
1486 bool pass = true;
1487 unsigned i;
1488 const struct object_type *object_type = NULL;
1489 const struct operation *operation = NULL;
1490 unsigned first_unused_texture;
1491 unsigned first_unused_framebuffer;
1493 if (argc != 3)
1494 usage(argv[0]);
1496 for (i = 0; i < ARRAY_SIZE(operation_table); i++) {
1497 if (strcmp(argv[1], operation_table[i].name) == 0) {
1498 operation = &operation_table[i];
1499 break;
1503 if (operation == NULL)
1504 usage(argv[0]);
1506 for (i = 0; i < ARRAY_SIZE(object_type_table); i++) {
1507 if (strcmp(argv[2], object_type_table[i].name) == 0) {
1508 object_type = &object_type_table[i];
1509 break;
1513 if (object_type == NULL)
1514 usage(argv[0]);
1516 printf("Test case %s with %s\n", object_type->name, operation->name);
1518 /* This is a bit ugly, but it is necessary. When a test is run with
1519 * -fbo, the piglit framework will create some textures before calling
1520 * piglit_init. These textures will likely have names that conflict
1521 * with the names that are used by this test, so the test should avoid
1522 * them.
1524 * HOWEVER, the test should only avoid lower numbered textures. If
1525 * the piglit framework created a texture named 1, the test should
1526 * still try to use a buffer object named 1.
1528 for (first_unused_texture = 1;
1529 first_unused_texture < 16;
1530 first_unused_texture++) {
1531 if (!glIsTexture(first_unused_texture))
1532 break;
1535 if (first_unused_texture >= 16)
1536 piglit_report_result(PIGLIT_FAIL);
1538 for (first_unused_framebuffer = 1;
1539 first_unused_framebuffer < 16;
1540 first_unused_framebuffer++) {
1541 if (!glIsFramebufferEXT(first_unused_framebuffer))
1542 break;
1545 if (first_unused_framebuffer >= 16)
1546 piglit_report_result(PIGLIT_FAIL);
1548 pass = operation->func() && pass;
1550 pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
1552 for (unsigned name = 1; name < 16; name++) {
1553 if (strcmp("texture", object_type->name) == 0 &&
1554 name < first_unused_texture)
1555 continue;
1557 if (strcmp("framebuffer", object_type->name) == 0 &&
1558 name < first_unused_framebuffer)
1559 continue;
1561 pass = object_type->create(name) && pass;
1564 pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
1566 pass = operation->func() && pass;
1568 pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
1570 for (unsigned name = 1; name < 16; name++) {
1571 if (strcmp("texture", object_type->name) == 0 &&
1572 name < first_unused_texture)
1573 continue;
1575 if (strcmp("framebuffer", object_type->name) == 0 &&
1576 name < first_unused_framebuffer)
1577 continue;
1579 pass = object_type->validate(name) && pass;
1582 pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
1584 piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
1587 enum piglit_result
1588 piglit_display(void)
1590 /* UNREACHABLE */
1591 return PIGLIT_FAIL;