Test glTexSubImage and glCopyTexSubImage rate.
authorBrian Paul <brian.paul@tungstengraphics.com>
Thu, 26 Jan 2006 17:35:31 +0000 (17:35 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Thu, 26 Jan 2006 17:35:31 +0000 (17:35 +0000)
Run with -nodraw to skip rendering of test quad to get "pure" sub-tex rate.

progs/tests/Makefile
progs/tests/subtexrate.c [new file with mode: 0644]

index 49ea7477e89bdc05f1e95ce6a161aad89838c76e..6cb52770e8069e68994ffa9c28d6beccccf2a425 100644 (file)
@@ -48,6 +48,7 @@ SOURCES = antialias.c \
        sharedtex.c \
        stencilwrap.c \
        stencil_wrap.c \
+       subtexrate.c \
        tex1d.c \
        texfilt.c \
        texline.c \
diff --git a/progs/tests/subtexrate.c b/progs/tests/subtexrate.c
new file mode 100644 (file)
index 0000000..f88fdc1
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Measure glTexSubImage and glCopyTexSubImage speed
+ *
+ * Brian Paul
+ * 26 Jan 2006
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static GLint WinWidth = 1024, WinHeight = 512;
+static GLint TexWidth = 512, TexHeight = 512;
+
+static GLuint TexObj = 1;
+
+static GLenum IntFormat = GL_RGBA8;
+static GLenum ReadFormat = GL_RGBA; /* for glReadPixels */
+
+static GLboolean DrawQuad = GL_TRUE;
+
+
+/**
+ * draw teapot image, size TexWidth by TexHeight
+ */
+static void
+DrawTestImage(void)
+{
+   GLfloat ar;
+
+   glViewport(0, 0, TexWidth, TexHeight);
+   glScissor(0, 0, TexWidth, TexHeight);
+   glEnable(GL_SCISSOR_TEST);
+
+   glClearColor(0.5, 0.5, 0.5, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   ar = (float) TexWidth / TexHeight;
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustum(-ar, ar, -1.0, 1.0, 5.0, 25.0);
+   glMatrixMode(GL_MODELVIEW);
+
+   glEnable(GL_LIGHTING);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_DEPTH_TEST);
+   glFrontFace(GL_CW);
+   glPushMatrix();
+   glRotatef(45, 1, 0, 0);
+   glRotatef(45, 0, 1, 0);
+   glutSolidTeapot(2.3);
+   glPopMatrix();
+   glFrontFace(GL_CCW);
+   glDisable(GL_DEPTH_TEST);
+   glDisable(GL_LIGHTING);
+
+   glDisable(GL_SCISSOR_TEST);
+
+   glViewport(0, 0, WinWidth, WinHeight);
+   glFinish();
+}
+
+
+/**
+ * Do glCopyTexSubImage2D call (update texture with framebuffer data)
+ * If doSubRect is true, do the copy in four pieces instead of all at once.
+ */
+static void
+DoCopyTex(GLboolean doSubRect)
+{
+   if (doSubRect) {
+      /* copy in four parts */
+      int w = TexWidth / 2, h = TexHeight / 2;
+      int x0 = 0, y0 = 0;
+      int x1 = w, y1 = h;
+#if 1
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, x0, y0, w, h);
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y0, x1, y0, w, h);
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y1, x0, y1, w, h);
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y1, x1, y1, w, h);
+#else
+      /* scramble */
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, x1, y1, w, h);
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y0, x0, y1, w, h);
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y1, x1, y0, w, h);
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y1, x0, y0, w, h);
+#endif
+   }
+   else {
+      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TexWidth, TexHeight);
+   }
+}
+
+
+/**
+ * Do glTexSubImage2D (update texture w/ user data)
+ * If doSubRect, do update in four pieces, else all at once.
+ */
+static void
+SubTex(GLboolean doSubRect, const GLubyte *image)
+{
+   if (doSubRect) {
+      /* four pieces */
+      int w = TexWidth / 2, h = TexHeight / 2;
+      int x0 = 0, y0 = 0;
+      int x1 = w, y1 = h;
+      glPixelStorei(GL_UNPACK_ROW_LENGTH, TexWidth);
+      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+      glPixelStorei(GL_UNPACK_SKIP_ROWS, y0);
+      glPixelStorei(GL_UNPACK_SKIP_PIXELS, x0);
+      glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, w, h,
+                      ReadFormat, GL_UNSIGNED_BYTE, image);
+
+      glPixelStorei(GL_UNPACK_SKIP_ROWS, y0);
+      glPixelStorei(GL_UNPACK_SKIP_PIXELS, x1);
+      glTexSubImage2D(GL_TEXTURE_2D, 0, x1, y0, w, h,
+                      ReadFormat, GL_UNSIGNED_BYTE, image);
+
+      glPixelStorei(GL_UNPACK_SKIP_ROWS, y1);
+      glPixelStorei(GL_UNPACK_SKIP_PIXELS, x0);
+      glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y1, w, h,
+                      ReadFormat, GL_UNSIGNED_BYTE, image);
+
+      glPixelStorei(GL_UNPACK_SKIP_ROWS, y1);
+      glPixelStorei(GL_UNPACK_SKIP_PIXELS, x1);
+      glTexSubImage2D(GL_TEXTURE_2D, 0, x1, y1, w, h,
+                      ReadFormat, GL_UNSIGNED_BYTE, image);
+   }
+   else {
+      /* all at once */
+      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexWidth, TexHeight,
+                      ReadFormat, GL_UNSIGNED_BYTE, image);
+   }
+}
+
+
+/**
+ * Measure gl[Copy]TexSubImage rate.
+ * This actually also includes time to render a quad and SwapBuffers.
+ */
+static void
+RunTest(GLboolean copyTex, GLboolean doSubRect)
+{
+   double t1, t0 = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+   int iters = 0;
+   float copyRate, mbRate;
+   float rot = 0.0;
+   int bpp, r, g, b, a;
+   int w, h;
+   GLubyte *image = NULL;
+
+   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, &r);
+   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_SIZE, &g);
+   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_SIZE, &b);
+   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &a);
+   bpp = (r + g + b + a) / 8;
+
+   if (!copyTex) {
+      /* read image from frame buffer */
+      image = (GLubyte *) malloc(TexWidth * TexHeight * bpp);
+      glPixelStorei(GL_PACK_ALIGNMENT, 1);
+      glReadPixels(0, 0, TexWidth, TexHeight,
+                   ReadFormat, GL_UNSIGNED_BYTE, image);
+   }
+
+   glEnable(GL_TEXTURE_2D);
+   glViewport(WinWidth / 2, 0, WinWidth / 2, WinHeight);
+
+   do {
+      if (copyTex)
+         /* Framebuffer -> Texture */
+         DoCopyTex(doSubRect);
+      else {
+         /* Main Mem -> Texture */
+         SubTex(doSubRect, image);
+      }
+
+      /* draw textured quad */
+      if (DrawQuad) {
+         glPushMatrix();
+            glRotatef(rot, 0, 0, 1);
+            glTranslatef(1, 0, 0);
+            glBegin(GL_POLYGON);
+               glTexCoord2f(0, 0);  glVertex2f(-1, -1);
+               glTexCoord2f(1, 0);  glVertex2f( 1, -1);
+               glTexCoord2f(1, 1);  glVertex2f( 1,  1);
+               glTexCoord2f(0, 1);  glVertex2f(-1,  1);
+            glEnd();
+         glPopMatrix();
+      }
+
+      iters++;
+      rot += 2.0;
+
+      t1 = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+      glutSwapBuffers();
+   } while (t1 - t0 < 5.0);
+
+   glDisable(GL_TEXTURE_2D);
+   if (image)
+      free(image);
+
+   if (doSubRect) {
+      w = TexWidth / 2;
+      h = TexHeight / 2;
+      iters *= 4;
+   }
+   else {
+      w = TexWidth;
+      h = TexHeight;
+   }
+
+   copyRate = iters / (t1 - t0);
+   mbRate = w * h * bpp * copyRate / (1024 * 1024);
+
+   if (copyTex)
+      printf("glCopyTexSubImage: %d x %d, %d Bpp:\n", w, h, bpp);
+   else
+      printf("glTexSubImage: %d x %d, %d Bpp:\n", w, h, bpp);
+   printf("   %d calls in %.2f = %.2f calls/sec, %.2f MB/s\n",
+          iters, t1-t0, copyRate, mbRate);
+}
+
+
+static void
+Draw(void)
+{
+   glClearColor(0.2, 0.2, 0.8, 0);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   DrawTestImage();
+
+   RunTest(GL_FALSE, GL_FALSE);
+   RunTest(GL_FALSE, GL_TRUE);
+   RunTest(GL_TRUE, GL_FALSE);
+   RunTest(GL_TRUE, GL_TRUE);
+
+   glutSwapBuffers();
+
+   printf("exiting\n");
+   exit(0);
+}
+
+
+static void
+Reshape(int width, int height)
+{
+   glViewport(0, 0, width, height);
+   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);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+   (void) x;
+   (void) y;
+   switch (key) {
+      case 27:
+         exit(0);
+         break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+   (void) x;
+   (void) y;
+   switch (key) {
+      case GLUT_KEY_UP:
+         break;
+      case GLUT_KEY_DOWN:
+         break;
+      case GLUT_KEY_LEFT:
+         break;
+      case GLUT_KEY_RIGHT:
+         break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+   /* create initial, empty teximage */
+   glBindTexture(GL_TEXTURE_2D, TexObj);
+   glTexImage2D(GL_TEXTURE_2D, 0, IntFormat, TexWidth, TexHeight, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+}
+
+
+
+static void
+ParseArgs(int argc, char *argv[])
+{
+   int i;
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "-nodraw") == 0)
+         DrawQuad = GL_FALSE;
+   }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   GLint mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH;
+   glutInit(&argc, argv);
+
+   ParseArgs(argc, argv);
+
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(WinWidth, WinHeight);
+   glutInitDisplayMode(mode);
+   glutCreateWindow(argv[0]);
+   glutReshapeFunc(Reshape);
+   glutKeyboardFunc(Key);
+   glutSpecialFunc(SpecialKey);
+   glutDisplayFunc(Draw);
+
+   printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
+   Init();
+
+   glutMainLoop();
+   return 0;
+}