1/*
2 * Test glReadPixels speed
3 * Brian Paul
4 * 9 April 2004
5 *
6 * Compile:
7 * gcc readrate.c -L/usr/X11R6/lib -lglut -lGLU -lGL -lX11 -o readrate
8 */
9
10#include <assert.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <math.h>
14#include <GL/glew.h>
15#include "glut_wrap.h"
16
17/* Hack, to test drawing instead of reading */
18#define DRAW 0
19
20#define MAX_WIDTH 1280
21#define MAX_HEIGHT 1024
22
23#define NUM_WIDTHS 4
24#define NUM_HEIGHTS 4
25static const GLint Widths[] = {256, 512, 1024, 1280};
26static const GLint Heights[] = {4, 32, 256, 512, 768, 1024};
27static int WidthIndex = 1, HeightIndex = 3;
28static GLubyte *Buffer = NULL;
29static GLboolean Benchmark = GL_TRUE;
30
31#define NUM_PBO 2
32
33static GLuint PBObjects[4];
34
35static GLboolean HavePBO = GL_FALSE;
36
37
38struct format_type {
39   const char *Name;
40   GLuint Bytes;
41   GLenum Format;
42   GLenum Type;
43};
44
45static struct format_type Formats[] = {
46   { "GL_RGB, GLubyte", 3, GL_RGB, GL_UNSIGNED_BYTE },
47   { "GL_BGR, GLubyte", 3, GL_BGR, GL_UNSIGNED_BYTE },
48   { "GL_RGBA, GLubyte", 4, GL_RGBA, GL_UNSIGNED_BYTE },
49   { "GL_BGRA, GLubyte", 4, GL_BGRA, GL_UNSIGNED_BYTE },
50   { "GL_ABGR, GLubyte", 4, GL_ABGR_EXT, GL_UNSIGNED_BYTE },
51   { "GL_RGBA, GLuint_8_8_8_8", 4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 },
52   { "GL_BGRA, GLuint_8_8_8_8", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8 },
53   { "GL_BGRA, GLuint_8_8_8_8_rev", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV },
54#ifdef GL_EXT_packed_depth_stencil
55   { "GL_DEPTH_STENCIL_EXT, GLuint24+8", 4, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT },
56#endif
57   { "GL_DEPTH_COMPONENT, GLfloat", 4, GL_DEPTH_COMPONENT, GL_FLOAT },
58   { "GL_DEPTH_COMPONENT, GLuint", 4, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }
59};
60
61#define NUM_FORMATS (sizeof(Formats) / sizeof(struct format_type))
62
63
64static void
65PrintString(const char *s)
66{
67   while (*s) {
68      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
69      s++;
70   }
71}
72
73
74static void
75MeasureFormat(struct format_type *fmt, GLint width, GLint height, GLuint pbo)
76{
77   double t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
78   double t1;
79   int j;
80
81   for (j = 0; ; j++) {
82
83      glBegin(GL_POINTS);
84      glVertex2f(1,1);
85      glEnd();
86
87#if DRAW
88      glWindowPos2iARB(0,0);
89      glDrawPixels(width, height,
90                   fmt->Format, fmt->Type, Buffer);
91      glFinish();
92#else
93      if (pbo) {
94         glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, PBObjects[j % NUM_PBO]);
95         glReadPixels(0, 0, width, height,
96                      fmt->Format, fmt->Type, 0);
97      }
98      else {
99         glReadPixels(0, 0, width, height,
100                      fmt->Format, fmt->Type, Buffer);
101      }
102#endif
103
104      t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
105      if (t1 - t0 > 2.0) {
106         GLdouble rate = width * height / (1024.0 * 1024.0) * j / (t1 - t0);
107#if DRAW
108         printf("%-32s  %.2f draws/sec %.2f MPixels/sec  %.2f MBytes/sec\n",
109                fmt->Name, j / (t1-t0), rate, rate * fmt->Bytes);
110#else
111         printf("%-32s  %.2f reads/sec %.2f MPixels/sec  %.2f MBytes/sec\n",
112                fmt->Name, j / (t1-t0), rate, rate * fmt->Bytes);
113#endif
114         break;
115      }
116
117      if (j == 0) {
118         /* check for error */
119         GLenum err = glGetError();
120         if (err) {
121            printf("GL Error 0x%x for %s\n", err, fmt->Name);
122            return;
123         }
124      }
125   }
126}
127
128
129
130static void
131Draw(void)
132{
133   char str[1000];
134   int width = Widths[WidthIndex];
135   int height = Heights[HeightIndex];
136   int y = MAX_HEIGHT - 50;
137
138   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
139
140   glWindowPos2iARB(10, y);
141   sprintf(str, "ReadPixels size: %d x %d", width, height);
142   PrintString(str);
143   y -= 14;
144
145   glWindowPos2iARB(10, y);
146   PrintString("Press up/down/left/right to change image size.");
147   y -= 14;
148
149   glWindowPos2iARB(10, y);
150   PrintString("Press 'b' to run benchmark test.");
151   y -= 14;
152
153   if (Benchmark) {
154      glWindowPos2iARB(10, y);
155      PrintString("Testing...");
156   }
157
158   glutSwapBuffers();
159
160   if (Benchmark) {
161      GLuint i, pbo;
162#if DRAW
163      printf("Draw size: Width=%d Height=%d\n", width, height);
164#else
165      printf("Read size: Width=%d Height=%d\n", width, height);
166#endif
167      for (pbo = 0; pbo <= HavePBO; pbo++) {
168         printf("Pixel Buffer Object: %d\n", pbo);
169
170         if (pbo == 0) {
171            glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
172         }
173
174         for (i = 0; i < NUM_FORMATS; i++) {
175            MeasureFormat(Formats + i, width, height, pbo);
176         }
177      }
178
179      Benchmark = GL_FALSE;
180
181      /* redraw window text */
182      glutPostRedisplay();
183   }
184
185}
186
187
188static void
189Reshape(int width, int height)
190{
191   glViewport(0, 0, width, height);
192   glMatrixMode(GL_PROJECTION);
193   glLoadIdentity();
194   glOrtho(-1, 1, -1, 1, -1, 1);
195   glMatrixMode(GL_MODELVIEW);
196   glLoadIdentity();
197}
198
199
200static void
201Key(unsigned char key, int x, int y)
202{
203   (void) x;
204   (void) y;
205   switch (key) {
206      case 'b':
207         Benchmark = 1;
208         break;
209      case 27:
210         exit(0);
211         break;
212   }
213   glutPostRedisplay();
214}
215
216
217static void
218SpecialKey(int key, int x, int y)
219{
220   (void) x;
221   (void) y;
222   switch (key) {
223      case GLUT_KEY_UP:
224         if (HeightIndex + 1 < NUM_WIDTHS)
225            HeightIndex++;
226         break;
227      case GLUT_KEY_DOWN:
228         if (HeightIndex > 0)
229            HeightIndex--;
230         break;
231      case GLUT_KEY_LEFT:
232         if (WidthIndex > 0)
233            WidthIndex--;
234         break;
235      case GLUT_KEY_RIGHT:
236         if (WidthIndex + 1 < NUM_HEIGHTS)
237            WidthIndex++;
238         break;
239   }
240   glutPostRedisplay();
241}
242
243
244static void
245Init(void)
246{
247   Buffer = malloc(MAX_WIDTH * MAX_HEIGHT * 4);
248   assert(Buffer);
249#if DRAW
250   printf("glDrawPixels test report:\n");
251#else
252   printf("glReadPixels test report:\n");
253#endif
254   printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
255   printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
256
257   if (glutExtensionSupported("GL_ARB_pixel_buffer_object")) {
258      int i;
259      HavePBO = 1;
260      glGenBuffersARB(NUM_PBO, PBObjects);
261      for (i = 0; i < NUM_PBO; i++) {
262         glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, PBObjects[i]);
263         glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT,
264                         MAX_WIDTH * MAX_HEIGHT * 4, NULL, GL_STREAM_READ);
265      }
266   }
267}
268
269
270int
271main(int argc, char *argv[])
272{
273   glutInit(&argc, argv);
274   glutInitWindowPosition(0, 0);
275   glutInitWindowSize(MAX_WIDTH, MAX_HEIGHT);
276   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
277   glutCreateWindow(argv[0]);
278   glewInit();
279   glutReshapeFunc(Reshape);
280   glutKeyboardFunc(Key);
281   glutSpecialFunc(SpecialKey);
282   glutDisplayFunc(Draw);
283   Init();
284   glutMainLoop();
285   return 0;
286}
287