--- /dev/null
+/*
+ * Test glReadPixels speed
+ * Brian Paul
+ * 9 April 2004
+ *
+ * Compile:
+ * gcc readrate.c -L/usr/X11R6/lib -lglut -lGLU -lGL -lX11 -o readrate
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+/* Hack, to test drawing instead of reading */
+#define DRAW 0
+
+#define MAX_WIDTH 1280
+#define MAX_HEIGHT 1024
+
+#define NUM_WIDTHS 4
+#define NUM_HEIGHTS 4
+static const GLint Widths[] = {256, 512, 1024, 1280};
+static const GLint Heights[] = {4, 32, 256, 512, 768, 1024};
+static int WidthIndex = 1, HeightIndex = 3;
+static GLubyte *Buffer = NULL;
+static GLboolean Benchmark = GL_TRUE;
+
+#define NUM_PBO 2
+
+static GLuint PBObjects[4];
+
+static GLboolean HavePBO = GL_FALSE;
+
+
+struct format_type {
+ const char *Name;
+ GLuint Bytes;
+ GLenum Format;
+ GLenum Type;
+};
+
+static struct format_type Formats[] = {
+ { "GL_RGB, GLubyte", 3, GL_RGB, GL_UNSIGNED_BYTE },
+ { "GL_BGR, GLubyte", 3, GL_BGR, GL_UNSIGNED_BYTE },
+ { "GL_RGBA, GLubyte", 4, GL_RGBA, GL_UNSIGNED_BYTE },
+ { "GL_BGRA, GLubyte", 4, GL_BGRA, GL_UNSIGNED_BYTE },
+ { "GL_ABGR, GLubyte", 4, GL_ABGR_EXT, GL_UNSIGNED_BYTE },
+ { "GL_RGBA, GLuint_8_8_8_8", 4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 },
+ { "GL_BGRA, GLuint_8_8_8_8", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8 },
+ { "GL_BGRA, GLuint_8_8_8_8_rev", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV },
+#ifdef GL_EXT_packed_depth_stencil
+ { "GL_DEPTH_STENCIL_EXT, GLuint24+8", 4, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT },
+#endif
+ { "GL_DEPTH_COMPONENT, GLfloat", 4, GL_DEPTH_COMPONENT, GL_FLOAT },
+ { "GL_DEPTH_COMPONENT, GLuint", 4, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }
+};
+
+#define NUM_FORMATS (sizeof(Formats) / sizeof(struct format_type))
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void
+MeasureFormat(struct format_type *fmt, GLint width, GLint height, GLuint pbo)
+{
+ double t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
+ double t1;
+ int j;
+
+ for (j = 0; ; j++) {
+
+ glBegin(GL_POINTS);
+ glVertex2f(1,1);
+ glEnd();
+
+#if DRAW
+ glWindowPos2iARB(0,0);
+ glDrawPixels(width, height,
+ fmt->Format, fmt->Type, Buffer);
+ glFinish();
+#else
+ if (pbo) {
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, PBObjects[j % NUM_PBO]);
+ glReadPixels(0, 0, width, height,
+ fmt->Format, fmt->Type, 0);
+ }
+ else {
+ glReadPixels(0, 0, width, height,
+ fmt->Format, fmt->Type, Buffer);
+ }
+#endif
+
+ t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
+ if (t1 - t0 > 2.0) {
+ GLdouble rate = width * height / (1024.0 * 1024.0) * j / (t1 - t0);
+#if DRAW
+ printf("%-32s %.2f draws/sec %.2f MPixels/sec %.2f MBytes/sec\n",
+ fmt->Name, j / (t1-t0), rate, rate * fmt->Bytes);
+#else
+ printf("%-32s %.2f reads/sec %.2f MPixels/sec %.2f MBytes/sec\n",
+ fmt->Name, j / (t1-t0), rate, rate * fmt->Bytes);
+#endif
+ break;
+ }
+
+ if (j == 0) {
+ /* check for error */
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error 0x%x for %s\n", err, fmt->Name);
+ return;
+ }
+ }
+ }
+}
+
+
+
+static void
+Draw(void)
+{
+ char str[1000];
+ int width = Widths[WidthIndex];
+ int height = Heights[HeightIndex];
+ int y = MAX_HEIGHT - 50;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glWindowPos2iARB(10, y);
+ sprintf(str, "ReadPixels size: %d x %d", width, height);
+ PrintString(str);
+ y -= 14;
+
+ glWindowPos2iARB(10, y);
+ PrintString("Press up/down/left/right to change image size.");
+ y -= 14;
+
+ glWindowPos2iARB(10, y);
+ PrintString("Press 'b' to run benchmark test.");
+ y -= 14;
+
+ if (Benchmark) {
+ glWindowPos2iARB(10, y);
+ PrintString("Testing...");
+ }
+
+ glutSwapBuffers();
+
+ if (Benchmark) {
+ GLuint i, pbo;
+#if DRAW
+ printf("Draw size: Width=%d Height=%d\n", width, height);
+#else
+ printf("Read size: Width=%d Height=%d\n", width, height);
+#endif
+ for (pbo = 0; pbo <= HavePBO; pbo++) {
+ printf("Pixel Buffer Object: %d\n", pbo);
+
+ if (pbo == 0) {
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+ }
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ MeasureFormat(Formats + i, width, height, pbo);
+ }
+ }
+
+ Benchmark = GL_FALSE;
+
+ /* redraw window text */
+ glutPostRedisplay();
+ }
+
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'b':
+ Benchmark = 1;
+ break;
+ 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:
+ if (HeightIndex + 1 < NUM_WIDTHS)
+ HeightIndex++;
+ break;
+ case GLUT_KEY_DOWN:
+ if (HeightIndex > 0)
+ HeightIndex--;
+ break;
+ case GLUT_KEY_LEFT:
+ if (WidthIndex > 0)
+ WidthIndex--;
+ break;
+ case GLUT_KEY_RIGHT:
+ if (WidthIndex + 1 < NUM_HEIGHTS)
+ WidthIndex++;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ Buffer = malloc(MAX_WIDTH * MAX_HEIGHT * 4);
+ assert(Buffer);
+#if DRAW
+ printf("glDrawPixels test report:\n");
+#else
+ printf("glReadPixels test report:\n");
+#endif
+ printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
+
+ if (glutExtensionSupported("GL_ARB_pixel_buffer_object")) {
+ int i;
+ HavePBO = 1;
+ glGenBuffersARB(NUM_PBO, PBObjects);
+ for (i = 0; i < NUM_PBO; i++) {
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, PBObjects[i]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT,
+ MAX_WIDTH * MAX_HEIGHT * 4, NULL, GL_STREAM_READ);
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(MAX_WIDTH, MAX_HEIGHT);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Draw);
+ Init();
+ glutMainLoop();
+ return 0;
+}