#include <GL/glew.h>
#include <GL/freeglut.h>
#include <GL/gl.h>
#include <stdio.h>
#include <string.h>

#define WIN_WIDTH 1024
#define WIN_HEIGHT 768
#define REPETITIONS 500

#define PBO

static GLubyte data[WIN_WIDTH * WIN_HEIGHT * 4];

static void
display_cb (void)
{
  int i;
  int start_time, end_time;

  start_time = glutGet (GLUT_ELAPSED_TIME);

#ifdef PBO
  {
    GLuint pbo;

    glGenBuffers (1, &pbo);
    glBindBuffer (GL_PIXEL_PACK_BUFFER, pbo);

    for (i = 0; i < REPETITIONS; i++)
      {
        GLubyte *map_data;

        glBufferData (GL_PIXEL_PACK_BUFFER,
                      WIN_WIDTH * WIN_HEIGHT * 4,
                      NULL, /* data */
                      GL_DYNAMIC_READ);
        glReadPixels (0, 0,
                      WIN_WIDTH, WIN_HEIGHT,
                      GL_BGRA,
                      GL_UNSIGNED_BYTE,
                      NULL);
        map_data = glMapBuffer (GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
        memcpy (data, map_data, WIN_WIDTH * WIN_HEIGHT * 4);
        glUnmapBuffer (GL_PIXEL_PACK_BUFFER);
      }

    glDeleteBuffers (1, &pbo);
  }
#else

  for (i = 0; i < REPETITIONS; i++)
    glReadPixels (0, 0,
                  WIN_WIDTH, WIN_HEIGHT,
                  GL_BGRA,
                  GL_UNSIGNED_BYTE,
                  data);

#endif

  end_time = glutGet (GLUT_ELAPSED_TIME);

  printf ("elapsed = %f\n", (end_time - start_time) / 1000.0f);

  exit (0);
}

int
main (int argc, char **argv)
{
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA);
  glutInitWindowSize (1024, 768);
  glutCreateWindow ("Time read pixels");
  glutDisplayFunc (display_cb);
  glewInit ();

  glutMainLoop ();

  return 0;
}
