blob: 6bdda049071cd0087900855eb70191eebec4a09a [file] [log] [blame]
/*
* Test glReadPixels speed
* Brian Paul
* 9 April 2004
*
* Compile:
* gcc readrate.c -L/usr/X11R6/lib -lglut -lGLU -lGL -lX11 -o readrate
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glew.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]);
glewInit();
glutReshapeFunc(Reshape);
glutKeyboardFunc(Key);
glutSpecialFunc(SpecialKey);
glutDisplayFunc(Draw);
Init();
glutMainLoop();
return 0;
}