#include #include #include #include #include #include #include #include #include #include namespace pbobench_cpp { /* NOTE: glGenBuffers and glMapBuffer calls are like raw new expressions, so we must be careful about exception safety. */ class BOId: boost::noncopyable { public: BOId() { glGenBuffers(1, &m_id); } ~BOId() { glDeleteBuffers(1, &m_id); } GLuint id() { return m_id; } private: GLuint m_id; }; class PBO: boost::noncopyable { public: PBO(GLsizei size): m_size(size) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_id.id()); glBufferData(GL_PIXEL_UNPACK_BUFFER, m_size, NULL, GL_STREAM_DRAW); m_ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); assert(m_ptr != NULL); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } ~PBO() { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_id.id()); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } private: GLsizei m_size; BOId m_id; GLvoid *m_ptr; }; void pbo_bench() { /* With default libdrm, L=100, count=100000: N=100: 17.3us; N=1000: 19.9us; N=10000: 88.5us; N=20000: 205us; N=40000: 406us With my libdrm: N=100: 18.3us; N=1000: 18.0us; N=10000: 18.2us; N=20000: 18.9us; N=40000: 20.8us */ const unsigned N = 80000, L = 100, count = 100000; std::cout << "Allocating base_bufs..." << std::endl; boost::ptr_vector base_bufs(N); for (unsigned i = 0; i < N; ++i) base_bufs.push_back(new PBO(4000)); boost::mt19937 rng; boost::uniform_int ran_i(0, L-1); boost::uniform_int ran_size(1, 16384); boost::ptr_vector > bufs(L); // This only reserves the space for L pointers; the vector is still empty now // NOTE: bufs[i] gives the PBO itself, not a pointer to it for (unsigned i = 0; i < L; ++i) bufs.push_back(NULL); assert(bufs.size() == L); std::cout << "Beginning benchmark..." << std::endl; Glib::TimeVal tv_start, tv_end; tv_start.assign_current_time(); for (unsigned j = 0; j < count; ++j) { unsigned i = ran_i(rng); if (bufs.is_null(i)) { // Create a new one GLsizei size = ran_size(rng); bufs.replace(i, new PBO(size)); } else { // Free it bufs.replace(i, NULL); // Returns a smart pointer which automatically frees the PBO } } tv_end.assign_current_time(); tv_end.subtract(tv_start); std::cout << "iteration time = " << (tv_end.as_double() / count * 1e6) << " us" << std::endl; } } using namespace pbobench_cpp; int main(int argc, char **argv) { glutInit(&argc, argv); glutInitWindowSize(512, 512); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutCreateWindow("pbobench"); GLenum err = glewInit(); assert(err == GLEW_OK); assert(GLEW_VERSION_1_5); pbo_bench(); }