| /* |
| * 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; |
| } |