1/*
2 * GL_ARB_pixel_buffer_object test
3 *
4 * Command line options:
5 *    -w WIDTH -h HEIGHT   sets window size
6 *
7 */
8
9#include <math.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <GL/glew.h>
14#include "glut_wrap.h"
15
16
17#define ANIMATE 10
18#define PBO 11
19#define QUIT 100
20
21static GLuint DrawPBO;
22
23static GLboolean Animate = GL_TRUE;
24static GLboolean use_pbo = 1;
25static GLboolean whole_rect = 1;
26
27static GLfloat Drift = 0.0;
28static GLfloat drift_increment = 1/255.0;
29static GLfloat Xrot = 20.0, Yrot = 30.0;
30
31static GLuint Width = 1024;
32static GLuint Height = 512;
33
34
35static void Idle( void )
36{
37   if (Animate) {
38
39      Drift += drift_increment;
40      if (Drift >= 1.0)
41         Drift = 0.0;
42
43      glutPostRedisplay();
44   }
45}
46
47/*static int max( int a, int b ) { return a > b ? a : b; }*/
48
49#ifndef min
50static int min( int a, int b ) { return a < b ? a : b; }
51#endif
52
53static void DrawObject(void)
54{
55   GLint size = Width * Height * 4;
56
57   if (use_pbo) {
58      /* XXX: This is extremely important - semantically makes the buffer
59       * contents undefined, but in practice means that the driver can
60       * release the old copy of the texture and allocate a new one
61       * without waiting for outstanding rendering to complete.
62       */
63      glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, DrawPBO);
64      glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, size, NULL, GL_STREAM_DRAW_ARB);
65
66      {
67	 char *image = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY_ARB);
68
69	 printf("char %d\n", (unsigned char)(Drift * 255));
70
71	 memset(image, (unsigned char)(Drift * 255), size);
72
73	 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
74      }
75
76
77      /* BGRA is required for most hardware paths:
78       */
79      glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, Width, Height, 0,
80		   GL_BGRA, GL_UNSIGNED_BYTE, NULL);
81   }
82   else {
83      static char *image = NULL;
84
85      if (image == NULL)
86	 image = malloc(size);
87
88      glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
89
90      memset(image, (unsigned char)(Drift * 255), size);
91
92      /* BGRA should be the fast path for regular uploads as well.
93       */
94      glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, Width, Height, 0,
95		   GL_BGRA, GL_UNSIGNED_BYTE, image);
96   }
97
98   {
99      int x,y,w,h;
100
101      if (whole_rect) {
102	 x = y = 0;
103	 w = Width;
104	 h = Height;
105      }
106      else {
107	 x = y = 0;
108	 w = min(10, Width);
109	 h = min(10, Height);
110      }
111
112      glBegin(GL_QUADS);
113
114      glTexCoord2f( x, y);
115      glVertex2f( x, y );
116
117      glTexCoord2f( x, y + h);
118      glVertex2f( x, y + h);
119
120      glTexCoord2f( x + w + .5, y + h);
121      glVertex2f( x + w, y + h );
122
123      glTexCoord2f( x + w, y + .5);
124      glVertex2f( x + w, y );
125
126      glEnd();
127   }
128}
129
130
131
132static void Display( void )
133{
134   static GLint T0 = 0;
135   static GLint Frames = 0;
136   GLint t;
137
138   glClear( GL_COLOR_BUFFER_BIT );
139
140   glPushMatrix();
141      DrawObject();
142   glPopMatrix();
143
144   glutSwapBuffers();
145
146   Frames++;
147
148   t = glutGet(GLUT_ELAPSED_TIME);
149   if (t - T0 >= 1000) {
150      GLfloat seconds = (t - T0) / 1000.0;
151
152      GLfloat fps = Frames / seconds;
153      printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps);
154      fflush(stdout);
155
156      drift_increment = 2.2 * seconds / Frames;
157      T0 = t;
158      Frames = 0;
159   }
160}
161
162
163static void Reshape( int width, int height )
164{
165   glViewport( 0, 0, width, height );
166   glMatrixMode( GL_PROJECTION );
167   glLoadIdentity();
168/*    glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 ); */
169   gluOrtho2D( 0, width, height, 0 );
170   glMatrixMode( GL_MODELVIEW );
171   glLoadIdentity();
172   glTranslatef(0.375, 0.375, 0);
173}
174
175
176static void ModeMenu(int entry)
177{
178   if (entry==ANIMATE) {
179      Animate = !Animate;
180   }
181   else if (entry==PBO) {
182      use_pbo = !use_pbo;
183   }
184   else if (entry==QUIT) {
185      exit(0);
186   }
187
188   glutPostRedisplay();
189}
190
191
192static void Key( unsigned char key, int x, int y )
193{
194   (void) x;
195   (void) y;
196   switch (key) {
197      case 27:
198         exit(0);
199         break;
200   }
201   glutPostRedisplay();
202}
203
204
205static void SpecialKey( int key, int x, int y )
206{
207   float step = 3.0;
208   (void) x;
209   (void) y;
210
211   switch (key) {
212      case GLUT_KEY_UP:
213         Xrot += step;
214         break;
215      case GLUT_KEY_DOWN:
216         Xrot -= step;
217         break;
218      case GLUT_KEY_LEFT:
219         Yrot += step;
220         break;
221      case GLUT_KEY_RIGHT:
222         Yrot -= step;
223         break;
224   }
225   glutPostRedisplay();
226}
227
228
229static void Init( int argc, char *argv[] )
230{
231   const char *exten = (const char *) glGetString(GL_EXTENSIONS);
232   GLuint texObj;
233   GLint size;
234
235
236   if (!strstr(exten, "GL_ARB_pixel_buffer_object")) {
237      printf("Sorry, GL_ARB_pixel_buffer_object not supported by this renderer.\n");
238      exit(1);
239   }
240
241   glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
242   printf("%d x %d max texture size\n", size, size);
243
244   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
245
246   /* allocate two texture objects */
247   glGenTextures(1, &texObj);
248
249   /* setup the texture objects */
250   glActiveTextureARB(GL_TEXTURE0_ARB);
251   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texObj);
252
253   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
254   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
255
256   glGenBuffersARB(1, &DrawPBO);
257
258   glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, DrawPBO);
259   glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT,
260		   Width * Height * 4, NULL, GL_STREAM_DRAW);
261
262   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
263
264   glEnable(GL_TEXTURE_RECTANGLE_ARB);
265
266   glShadeModel(GL_SMOOTH);
267   glClearColor(0.3, 0.3, 0.4, 1.0);
268
269   if (argc > 1 && strcmp(argv[1], "-info")==0) {
270      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
271      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
272      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
273      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
274   }
275}
276
277
278int main( int argc, char *argv[] )
279{
280   GLint i;
281
282   glutInit( &argc, argv );
283
284   for (i = 1; i < argc; i++) {
285      if (strcmp(argv[i], "-w") == 0) {
286         Width = atoi(argv[i+1]);
287         if (Width <= 0) {
288            printf("Error, bad width\n");
289            exit(1);
290         }
291         i++;
292      }
293      else if (strcmp(argv[i], "-h") == 0) {
294         Height = atoi(argv[i+1]);
295         if (Height <= 0) {
296            printf("Error, bad height\n");
297            exit(1);
298         }
299         i++;
300      }
301   }
302
303   glutInitWindowSize( Width, Height );
304   glutInitWindowPosition( 0, 0 );
305   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
306   glutCreateWindow(argv[0] );
307   glewInit();
308
309   Init( argc, argv );
310
311   glutReshapeFunc( Reshape );
312   glutKeyboardFunc( Key );
313   glutSpecialFunc( SpecialKey );
314   glutDisplayFunc( Display );
315   glutIdleFunc( Idle );
316
317   glutCreateMenu(ModeMenu);
318   glutAddMenuEntry("Toggle Animation", ANIMATE);
319   glutAddMenuEntry("Toggle PBO", PBO);
320   glutAddMenuEntry("Quit", QUIT);
321   glutAttachMenu(GLUT_RIGHT_BUTTON);
322
323   glutMainLoop();
324   return 0;
325}
326