summaryrefslogtreecommitdiffstats
path: root/progs/tests
diff options
context:
space:
mode:
Diffstat (limited to 'progs/tests')
-rw-r--r--progs/tests/Makefile3
-rw-r--r--progs/tests/SConscript22
-rw-r--r--progs/tests/condrender.c242
-rw-r--r--progs/tests/drawbuffers2.c364
-rw-r--r--progs/tests/texleak.c140
5 files changed, 752 insertions, 19 deletions
diff --git a/progs/tests/Makefile b/progs/tests/Makefile
index 197e14d5b00..836396b2499 100644
--- a/progs/tests/Makefile
+++ b/progs/tests/Makefile
@@ -37,10 +37,12 @@ SOURCES = \
bug_3195.c \
bug_texstore_i8.c \
calibrate_rast.c \
+ condrender.c \
copypixrate.c \
crossbar.c \
cva.c \
drawbuffers.c \
+ drawbuffers2.c \
exactrast.c \
ext422square.c \
floattex.c \
@@ -98,6 +100,7 @@ SOURCES = \
texdown \
texfilt.c \
texgenmix.c \
+ texleak.c \
texline.c \
texobj.c \
texobjshare.c \
diff --git a/progs/tests/SConscript b/progs/tests/SConscript
index 3a0da62717c..e2c65382887 100644
--- a/progs/tests/SConscript
+++ b/progs/tests/SConscript
@@ -1,23 +1,5 @@
Import('*')
-if not env['GLUT']:
- Return()
-
-env = env.Clone()
-
-env.Prepend(CPPPATH = [
- '../util',
-])
-
-env.Prepend(LIBS = [
- util,
- '$GLUT_LIB'
-])
-
-if env['platform'] == 'windows':
- env.Append(CPPDEFINES = ['NOMINMAX'])
- env.Prepend(LIBS = ['winmm'])
-
linux_progs = [
'api_speed',
]
@@ -59,10 +41,12 @@ progs = [
'bug_3195',
'bug_texstore_i8',
'calibrate_rast',
+ 'condrender',
'copypixrate',
'crossbar',
'cva',
'drawbuffers',
+ 'drawbuffers2',
'exactrast',
'ext422square',
'fbotest1',
@@ -138,7 +122,7 @@ progs = [
]
for prog in progs:
- env.Program(
+ progs_env.Program(
target = prog,
source = prog + '.c',
)
diff --git a/progs/tests/condrender.c b/progs/tests/condrender.c
new file mode 100644
index 00000000000..1db8a7c15af
--- /dev/null
+++ b/progs/tests/condrender.c
@@ -0,0 +1,242 @@
+/*
+ * Test GL_NV_conditional_render
+ *
+ * Brian Paul
+ * 30 Dec 2009
+ *
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * 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 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 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.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glew.h>
+#include <GL/glut.h>
+
+#define TEST_DISPLAY_LISTS 0
+
+static GLboolean Anim = GL_TRUE;
+static GLfloat Xpos = 0;
+static GLuint OccQuery;
+static GLint Win = 0;
+
+
+static void Idle(void)
+{
+ static int lastTime = 0;
+ static int sign = +1;
+ int time = glutGet(GLUT_ELAPSED_TIME);
+ float step;
+
+ if (lastTime == 0)
+ lastTime = time;
+ else if (time - lastTime < 20) /* 50Hz update */
+ return;
+
+ step = (time - lastTime) / 1000.0 * sign;
+ lastTime = time;
+
+ Xpos += step;
+
+ if (Xpos > 2.5) {
+ Xpos = 2.5;
+ sign = -1;
+ }
+ else if (Xpos < -2.5) {
+ Xpos = -2.5;
+ sign = +1;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glEnable(GL_DEPTH_TEST);
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+
+ /* draw the occluding polygons */
+ glColor3f(0, 0.6, 0.8);
+ glBegin(GL_QUADS);
+ glVertex2f(-1.6, -1.5);
+ glVertex2f(-0.4, -1.5);
+ glVertex2f(-0.4, 1.5);
+ glVertex2f(-1.6, 1.5);
+
+ glVertex2f( 0.4, -1.5);
+ glVertex2f( 1.6, -1.5);
+ glVertex2f( 1.6, 1.5);
+ glVertex2f( 0.4, 1.5);
+ glEnd();
+
+ /* draw the test polygon with occlusion testing */
+ glPushMatrix();
+ glTranslatef(Xpos, 0, -0.5);
+ glScalef(0.3, 0.3, 1.0);
+ glRotatef(-90.0 * Xpos, 0, 0, 1);
+
+#if TEST_DISPLAY_LISTS
+ glNewList(10, GL_COMPILE);
+ glBeginQueryARB(GL_SAMPLES_PASSED_ARB, OccQuery);
+ glEndList();
+ glCallList(10);
+#else
+ glBeginQueryARB(GL_SAMPLES_PASSED_ARB, OccQuery);
+#endif
+
+ glColorMask(0, 0, 0, 0);
+ glDepthMask(GL_FALSE);
+
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, 0);
+ glVertex3f( 1, -1, 0);
+ glVertex3f( 1, 1, 0);
+ glVertex3f(-1, 1, 0);
+ glEnd();
+
+#if TEST_DISPLAY_LISTS
+ glNewList(11, GL_COMPILE);
+ glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+ glEndList();
+ glCallList(11);
+#else
+ glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+#endif
+
+ glColorMask(1, 1, 1, 1);
+ glDepthMask(GL_TRUE);
+
+ /* Note: disable depth test here so that we'll always see the orange
+ * box, except when it's totally culled.
+ */
+ glDisable(GL_DEPTH_TEST);
+
+ glBeginConditionalRenderNV(OccQuery, GL_QUERY_WAIT_NV);
+ /* draw the orange rect, so we can see what's going on */
+ glColor3f(0.8, 0.5, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, 0);
+ glVertex3f( 1, -1, 0);
+ glVertex3f( 1, 1, 0);
+ glVertex3f(-1, 1, 0);
+ glEnd();
+ glEndConditionalRenderNV();
+
+ /* always draw white outline around orange box */
+ glColor3f(1.0, 1.0, 1.0);
+ glBegin(GL_LINE_LOOP);
+ glVertex3f(-1, -1, 0);
+ glVertex3f( 1, -1, 0);
+ glVertex3f( 1, 1, 0);
+ glVertex3f(-1, 1, 0);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ glDeleteQueriesARB(1, &OccQuery);
+ glutDestroyWindow(Win);
+ exit(0);
+ break;
+ case ' ':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 0.1;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_LEFT:
+ Xpos -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Xpos += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ if (!glutExtensionSupported("GL_ARB_occlusion_query") ||
+ !glutExtensionSupported("GL_NV_conditional_render")) {
+ printf("Sorry, this demo requires the extensions:\n");
+ printf(" GL_ARB_occlusion_query\n");
+ printf(" GL_NV_conditional_render\n");
+ exit(-1);
+ }
+
+ glGenQueriesARB(1, &OccQuery);
+ assert(OccQuery > 0);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInitWindowSize( 400, 400 );
+ glutInit( &argc, argv );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ Win = glutCreateWindow(argv[0]);
+ glewInit();
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutIdleFunc( Idle );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/progs/tests/drawbuffers2.c b/progs/tests/drawbuffers2.c
new file mode 100644
index 00000000000..7b8cc5ca6a3
--- /dev/null
+++ b/progs/tests/drawbuffers2.c
@@ -0,0 +1,364 @@
+/*
+ * Test GL_ARB_draw_buffers2, GL_ARB_draw_buffers, GL_EXT_framebuffer_object
+ * and GLSL's gl_FragData[].
+ *
+ * We draw to two color buffers and show the left half of the first
+ * color buffer on the left side of the window, and show the right
+ * half of the second color buffer on the right side of the window.
+ *
+ * Different color masks are used for the two color buffers.
+ * Blending is enabled for the second buffer only.
+ *
+ * Brian Paul
+ * 31 Dec 2009
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glew.h>
+#include <GL/glut.h>
+#include "extfuncs.h"
+
+static int Win;
+static int Width = 400, Height = 400;
+static GLuint FBobject, RBobjects[3];
+static GLfloat Xrot = 0.0, Yrot = 0.0;
+static GLuint Program;
+static GLboolean Anim = GL_TRUE;
+
+
+static void
+CheckError(int line)
+{
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error 0x%x at line %d\n", (int) err, line);
+ }
+}
+
+
+static void
+Display(void)
+{
+ GLubyte *buffer = malloc(Width * Height * 4);
+ static const GLenum buffers[2] = {
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_COLOR_ATTACHMENT1_EXT
+ };
+
+ glUseProgram_func(Program);
+
+ glEnable(GL_DEPTH_TEST);
+
+ /* draw to user framebuffer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBobject);
+
+ /* Clear color buffer 0 (blue) */
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* Clear color buffer 1 (1 - blue) */
+ glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ /* draw to two buffers w/ fragment shader */
+ glDrawBuffersARB(2, buffers);
+
+ /* different color masks for each buffer */
+ if (1) {
+ glColorMaskIndexedEXT(0, GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glColorMaskIndexedEXT(1, GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
+ }
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glPushMatrix();
+ glTranslatef(1, 0, 0);
+ glutSolidTorus(1.0, 2.0, 10, 20);
+ glPopMatrix();
+ glPushMatrix();
+ glTranslatef(-1, 0, 0);
+ glRotatef(90, 1, 0, 0);
+ glutSolidTorus(1.0, 2.0, 10, 20);
+ glPopMatrix();
+ glPopMatrix();
+
+ /* restore default color masks */
+ glColorMaskIndexedEXT(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glColorMaskIndexedEXT(1, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ /* read from user framebuffer */
+ /* left half = colorbuffer 0 */
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glPixelStorei(GL_PACK_ROW_LENGTH, Width);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ glReadPixels(0, 0, Width / 2, Height, GL_RGBA, GL_UNSIGNED_BYTE,
+ buffer);
+
+ /* right half = colorbuffer 1 */
+ glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, Width / 2);
+ glReadPixels(Width / 2, 0, Width - Width / 2, Height,
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ buffer);
+
+ /* draw to window */
+ glUseProgram_func(0);
+ glDisable(GL_DEPTH_TEST);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glWindowPos2iARB(0, 0);
+ glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ free(buffer);
+ glutSwapBuffers();
+ CheckError(__LINE__);
+}
+
+
+static void
+Idle(void)
+{
+ Xrot = glutGet(GLUT_ELAPSED_TIME) * 0.05;
+ glutPostRedisplay();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ float ar = (float) width / (float) height;
+
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-ar, ar, -1.0, 1.0, 5.0, 35.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -20.0);
+
+ Width = width;
+ Height = height;
+
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[0]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[1]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[2]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
+ Width, Height);
+}
+
+
+static void
+CleanUp(void)
+{
+ glDeleteFramebuffersEXT(1, &FBobject);
+ glDeleteRenderbuffersEXT(3, RBobjects);
+ glutDestroyWindow(Win);
+ exit(0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case ' ':
+ Anim = !Anim;
+ glutIdleFunc(Anim ? Idle : NULL);
+ break;
+ case 'x':
+ Xrot += 5.0;
+ break;
+ case 'X':
+ Xrot -= 5.0;
+ break;
+ case 'y':
+ Yrot += 5.0;
+ break;
+ case 'Y':
+ Yrot -= 5.0;
+ break;
+ case 27:
+ CleanUp();
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+CheckExtensions(void)
+{
+ const char *req[] = {
+ "GL_EXT_framebuffer_object",
+ "GL_ARB_draw_buffers",
+ "GL_EXT_draw_buffers2"
+ };
+
+ const char *version = (const char *) glGetString(GL_VERSION);
+ GLint numBuf;
+ GLint i;
+
+ for (i = 0; i < 3; i++) {
+ if (!glutExtensionSupported(req[i])) {
+ printf("Sorry, %s extension is required!\n", req[i]);
+ exit(1);
+ }
+ }
+ if (version[0] != '2') {
+ printf("Sorry, OpenGL 2.0 is required!\n");
+ exit(1);
+ }
+
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &numBuf);
+ printf("GL_MAX_DRAW_BUFFERS_ARB = %d\n", numBuf);
+ if (numBuf < 2) {
+ printf("Sorry, GL_MAX_DRAW_BUFFERS_ARB needs to be >= 2\n");
+ exit(1);
+ }
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+}
+
+
+static void
+SetupRenderbuffers(void)
+{
+ glGenFramebuffersEXT(1, &FBobject);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBobject);
+
+ glGenRenderbuffersEXT(3, RBobjects);
+
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[0]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height);
+
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[1]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height);
+
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[2]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
+ Width, Height);
+
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, RBobjects[0]);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
+ GL_RENDERBUFFER_EXT, RBobjects[1]);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, RBobjects[2]);
+
+ CheckError(__LINE__);
+}
+
+
+static GLuint
+LoadAndCompileShader(GLenum target, const char *text)
+{
+ GLint stat;
+ GLuint shader = glCreateShader_func(target);
+ glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
+ glCompileShader_func(shader);
+ glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetShaderInfoLog_func(shader, 1000, &len, log);
+ fprintf(stderr, "drawbuffers: problem compiling shader:\n%s\n", log);
+ exit(1);
+ }
+ return shader;
+}
+
+
+static void
+CheckLink(GLuint prog)
+{
+ GLint stat;
+ glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetProgramInfoLog_func(prog, 1000, &len, log);
+ fprintf(stderr, "drawbuffers: shader link error:\n%s\n", log);
+ }
+}
+
+
+static void
+SetupShaders(void)
+{
+ /* emit same color to both draw buffers */
+ static const char *fragShaderText =
+ "void main() {\n"
+ " gl_FragData[0] = gl_Color; \n"
+ " gl_FragData[1] = gl_Color; \n"
+ "}\n";
+
+ GLuint fragShader;
+
+ fragShader = LoadAndCompileShader(GL_FRAGMENT_SHADER, fragShaderText);
+ Program = glCreateProgram_func();
+
+ glAttachShader_func(Program, fragShader);
+ glLinkProgram_func(Program);
+ CheckLink(Program);
+ glUseProgram_func(Program);
+}
+
+
+static void
+SetupLighting(void)
+{
+ static const GLfloat ambient[4] = { 0.0, 0.0, 0.0, 0.0 };
+ static const GLfloat diffuse[4] = { 1.0, 1.0, 1.0, 0.75 };
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
+
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHTING);
+}
+
+
+static void
+Init(void)
+{
+ CheckExtensions();
+ GetExtensionFuncs();
+ SetupRenderbuffers();
+ SetupShaders();
+ SetupLighting();
+ glEnable(GL_DEPTH_TEST);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnableIndexedEXT(GL_BLEND, 1);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+ Win = glutCreateWindow(argv[0]);
+ glewInit();
+ glutIdleFunc(Anim ? Idle : NULL);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Display);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/progs/tests/texleak.c b/progs/tests/texleak.c
new file mode 100644
index 00000000000..5cf4ff32393
--- /dev/null
+++ b/progs/tests/texleak.c
@@ -0,0 +1,140 @@
+/*
+ * 'Texture leak' test
+ *
+ * Allocates and uses an additional texture of the maximum supported size for
+ * each frame. This tests the system's ability to cope with using increasing
+ * amounts of texture memory.
+ *
+ * Michel Dänzer July 2009 This program is in the public domain.
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <GL/glew.h>
+#include <GL/glut.h>
+
+
+GLint size;
+GLvoid *image;
+static GLuint numTexObj;
+static GLuint *texObj;
+
+
+static void Idle( void )
+{
+ glutPostRedisplay();
+}
+
+
+static void DrawObject(void)
+{
+ static const GLfloat tex_coords[] = { 0.0, 0.0, 1.0, 1.0, 0.0 };
+ static const GLfloat vtx_coords[] = { -1.0, -1.0, 1.0, 1.0, -1.0 };
+ GLint i, j;
+
+ glEnable(GL_TEXTURE_2D);
+
+ for (i = 0; i < numTexObj; i++) {
+ glBindTexture(GL_TEXTURE_2D, texObj[i]);
+ glBegin(GL_QUADS);
+ for (j = 0; j < 4; j++ ) {
+ glTexCoord2f(tex_coords[j], tex_coords[j+1]);
+ glVertex2f( vtx_coords[j], vtx_coords[j+1] );
+ }
+ glEnd();
+ }
+}
+
+
+static void Display( void )
+{
+ struct timeval start, end;
+
+ texObj = realloc(texObj, ++numTexObj * sizeof(*texObj));
+
+ /* allocate a texture object */
+ glGenTextures(1, texObj + (numTexObj - 1));
+
+ glBindTexture(GL_TEXTURE_2D, texObj[numTexObj - 1]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ memset(image, (16 * numTexObj) & 0xff, 4 * size * size);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+
+ gettimeofday(&start, NULL);
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glScalef(5.0, 5.0, 5.0);
+ DrawObject();
+ glPopMatrix();
+
+ glutSwapBuffers();
+
+ glFinish();
+ gettimeofday(&end, NULL);
+ printf("Rendering frame took %lu ms using %u MB of textures\n",
+ end.tv_sec * 1000 + end.tv_usec / 1000 - start.tv_sec * 1000 -
+ start.tv_usec / 1000, numTexObj * 4 * size / 1024 * size / 1024);
+
+ sleep(1);
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( -6.0, 6.0, -6.0, 6.0, 10.0, 100.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -70.0 );
+}
+
+
+static void Init( int argc, char *argv[] )
+{
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
+ printf("%d x %d max texture size\n", size, size);
+
+ image = malloc(4 * size * size);
+ if (!image) {
+ fprintf(stderr, "Failed to allocate %u bytes of memory\n", 4 * size * size);
+ exit(1);
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+
+ Idle();
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowSize( 300, 300 );
+ glutInitWindowPosition( 0, 0 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0] );
+ glewInit();
+
+ Init( argc, argv );
+
+ glutReshapeFunc( Reshape );
+ glutDisplayFunc( Display );
+ glutIdleFunc(Idle);
+
+ glutMainLoop();
+ return 0;
+}