| C vs Perl | Perl vs Python | POGL vs SDL | Windows vs Linux | POGL Benchmarks - C vs Perl Google digg it! Stumbled on It! del.icio.us reddit Slashdot It! This is a benchmark implemented in C and Perl, using animated FBOs and a fragment shader. Platforms These benchmarks were performed on the same multi-boot system:

3Ghz Intel Pentium D

1G Memory

nVidia GeForce 6800 GT/AGP/SSE2

Matched nVidia drivers (as of March, 15, 2007):



Linux: v97.55 Vista: v100.65 The tests were run using portable, non-OOP C and Perl code on:

Vista

Fedora 6 Ubuntu/Dapper The C benchmarks require an OpenGL installation and GLUT. The Perl benchmarks also require Perl, POGL and the Time::HiRes module. These tests were also run on a similar XP system, with similar results; however, since it was not possible to install XP after Vista and Linux were already installed on this benchmark system, those results were not included in this report. Summary

No statistical difference in overall performance between C and Perl

Perl outperformed C on FBO operations; C beat Perl on Shader ops

On Vista, Perl occasionally/often ran faster than C

Fedora and Ubuntu were comparable in performance Linux was generally 60% faster than Vista Results Vista Fedora 6 Ubuntu/Dapper PROFILE C Perl C Perl C Perl FBO Texture Rendering FPS 117.296043 137.680194 190.628178 192.675391 193.914733 194.749544 Teapot Shader FPS 267.217852 284.675682 479.408799 472.232557 472.171695 477.404038 Frame overhead secs/frame 0.000032 0.000126 0.000030 0.000071 0.000033 0.000067 OS/GLUT overhead secs/frame 0.000000 0.000050 0.000006 0.000014 0.000114 0.000114 TOTAL FPS 81.302792 91.315494 135.728814 135.275647 134.742228 134.945798 Analysis There are a number of factors explaining the lack of significant difference between C and Perl OpenGL performance:

POGL is a compiled C module

Most of the work is performed by the GPU POGL leverages OpenGL::Array (OGA) objects OGA stores data in typed C arrays, eliminating the need for conversion/copy/casting when passing array data to OpenGL APIs. Perl OpenGL provides a number of other advantages:

Completely portable, with no compiling; faster prototyping

Easy integration into LAMP-based online services Improved string handling for dynamic shader programming Source Code C Binding

// ogl_bench v1.0 - Copyright 2007 - Graphcomp // Bob Free bfree@graphcomp.com // http://graphcomp.com/opengl // This program is freely distributable without licensing fees // and is provided without guarantee or warrantee expressed or // implied. This program is -not- in the public domain. // Set up standard libs #include <stdlib.h> #include <sys/types.h> #include <sys/timeb.h> #include <stdio.h> #include <string.h> // Set up constants #define PROGRAM "OpenGL Benchmark - C Binding" #define CYCLES 1000 // Setup OpenGL Extensions #include <GL/glut.h> #ifdef _WIN32 #define GL_GLEXT_PROCS #define loadProc(proc,name) \ if (!proc) \ { \ proc = (void *)wglGetProcAddress(name); \ if (!proc) error("Unable to load",name); \ } #define timeb _timeb #define ftime _ftime #else #define GL_GLEXT_PROTOTYPES #define loadProc(proc,name) #endif #include "glext_procs.h" // Set up types typedef struct { struct timeb start; float secs; } Bench; // Set up globals Bench appBench; Bench frameBench; Bench textureBench; Bench teapotBench; struct timeb now; int frames = 0; GLuint idWindow = 0; GLint windowWidth = 512; GLint windowHeight = 512; GLint textureWidth = 128; GLint textureHeight = 128; GLfloat rotTeapotX = 0; GLfloat rotTeapotY = 0; GLuint idTexture = 0; GLuint idFrameBuffer = 0; GLuint idRenderBuffer = 0; GLuint idVertexProg = 0; GLuint idFragProg = 0; GLdouble incY = 0.5; GLdouble rotY = 0.0; // Start benchmark void startBench(Bench *pBench) { ftime(&pBench->start); } // Accumulate benchmark void endBench(Bench *pBench) { ftime(&now); pBench->secs += (float)(now.time - pBench->start.time) + (float)((now.millitm - pBench->start.millitm) / 1000.0); } // Print benchmark void printBench() { float overhead; if (!frames || !appBench.secs || !frameBench.secs || !textureBench.secs || !teapotBench.secs) { printf("No measurable time has elapsed

"); return; } printf("FBO Texture Rendering FPS: %f

", frames / textureBench.secs); printf("Teapot Shader FPS: %f

", frames / teapotBench.secs); overhead = frameBench.secs - (textureBench.secs + teapotBench.secs); printf("Frame overhead secs/frame: %f

", overhead / frames); overhead = appBench.secs - frameBench.secs; printf("OS/GLUT overhead secs/frame: %f

", overhead / frames); printf("Overall FPS: %f

", frames / appBench.secs); printf("

"); } // Error handling void error(char *errTitle, char *errMsg) { printf("%s: %s

", errTitle, errMsg); exit(0); } // Check OpenGL Version void checkVersion(void) { char *version = (char*)glGetString(GL_VERSION); char *vendor = (char*)glGetString(GL_VENDOR); char *renderer = (char*)glGetString(GL_RENDERER); char *exts = (char*)glGetString(GL_EXTENSIONS); printf("%s



", PROGRAM); printf("OpenGL: %s

", version); printf("Vendor: %s

", vendor); printf("Renderer: %s

", renderer); printf("

"); if (!strstr(exts,"EXT_framebuffer_object")) { error("Extension not available","EXT_framebuffer_object"); } } // Load Extension Procs void initExtensions(void) { loadProc(glIsRenderbufferEXT,"glIsRenderbufferEXT"); loadProc(glBindRenderbufferEXT,"glBindRenderbufferEXT"); loadProc(glDeleteRenderbuffersEXT,"glDeleteRenderbuffersEXT"); loadProc(glGenRenderbuffersEXT,"glGenRenderbuffersEXT"); loadProc(glRenderbufferStorageEXT,"glRenderbufferStorageEXT"); loadProc(glGetRenderbufferParameterivEXT,"glGetRenderbufferParameterivEXT"); loadProc(glIsFramebufferEXT,"glIsFramebufferEXT"); loadProc(glBindFramebufferEXT,"glBindFramebufferEXT"); loadProc(glDeleteFramebuffersEXT,"glDeleteFramebuffersEXT"); loadProc(glGenFramebuffersEXT,"glGenFramebuffersEXT"); loadProc(glCheckFramebufferStatusEXT,"glCheckFramebufferStatusEXT"); loadProc(glFramebufferTexture1DEXT,"glFramebufferTexture1DEXT"); loadProc(glFramebufferTexture2DEXT,"glFramebufferTexture2DEXT"); loadProc(glFramebufferTexture3DEXT,"glFramebufferTexture3DEXT"); loadProc(glFramebufferRenderbufferEXT,"glFramebufferRenderbufferEXT"); loadProc(glGetFramebufferAttachmentParameterivEXT,"glGetFramebufferAttachmentParameterivEXT"); loadProc(glGenerateMipmapEXT,"glGenerateMipmapEXT"); loadProc(glGenProgramsARB,"glGenProgramsARB"); loadProc(glBindProgramARB,"glBindProgramARB"); loadProc(glProgramStringARB,"glProgramStringARB"); loadProc(glDeleteProgramsARB,"glDeleteProgramsARB"); } // Initialize Vertex/Fragment Programs void initProgs(void) { // NOP Vertex shader const char *vertexProg = "!!ARBvp1.0

" "TEMP vertexClip;

" "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position;

" "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position;

" "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position;

" "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position;

" "MOV result.position, vertexClip;

" "MOV result.color, vertex.color;

" "MOV result.texcoord[0], vertex.texcoord;

" "MOV result.texcoord[1], vertex.normal;

" "END

"; // Black Light Fragment shader const char *fragProg = "!!ARBfp1.0

" "TEMP decal,color;

" "TEX decal, fragment.texcoord[0], texture[0], 2D;

" "MUL result.color, decal, fragment.texcoord[1];

" "END

"; glGenProgramsARB(1,&idVertexProg); glGenProgramsARB(1,&idFragProg); glBindProgramARB(GL_VERTEX_PROGRAM_ARB, idVertexProg); glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(vertexProg), vertexProg); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, idFragProg); glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(fragProg), fragProg); } // Terminate Vertex/Fragment Programs void termProgs(void) { glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); glDeleteProgramsARB(1,&idVertexProg); glDeleteProgramsARB(1,&idFragProg); } // FBO Status handler void statusFBO(void) { GLenum stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (!stat || stat == GL_FRAMEBUFFER_COMPLETE_EXT) {return;}; printf("FBO status: %04X

", stat); exit(0); } // Initialize Framebuffers void initFBO(void) { glGenTextures(1,&idTexture); glGenFramebuffersEXT(1,&idFrameBuffer); glGenRenderbuffersEXT(1,&idRenderBuffer); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, idFrameBuffer); glBindTexture(GL_TEXTURE_2D, idTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, idTexture, 0); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, idRenderBuffer); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, textureWidth, textureHeight); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, idRenderBuffer); statusFBO(); } // FBO texture renderer void renderFBO(void) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, idFrameBuffer); glLoadIdentity(); glTranslated(-0.75, -0.85, -2.5); glRotated(rotTeapotX, 1.0, 0.0, 0.0); rotTeapotX += .5; glRotated(rotTeapotY, 0.0, 1.0, 0.0); rotTeapotY += 1.0; glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3d(1.0, 1.0, 1.0); glutWireTeapot(0.125); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } // Terminate FBO objects void termFBO(void) { glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindTexture(GL_TEXTURE_2D, 0); glDeleteRenderbuffersEXT(1,&idRenderBuffer); glDeleteFramebuffersEXT(1,&idFrameBuffer); glDeleteTextures(1,&idTexture); } // Resize Window void resizeScene(GLint width, GLint height) { if (!height){height = 1;}; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0,width/height,0.1,100.0); glMatrixMode(GL_MODELVIEW); windowWidth = width; windowHeight = height; } // Initialize OpenGL Environment void init(void) { checkVersion(); initExtensions(); resizeScene(windowWidth, windowHeight); initFBO(); initProgs(); } // Terminate OpenGL Environment void term(void) { // Display benchmark endBench(&appBench); printBench(); // Disable app glutHideWindow(); glutKeyboardFunc(0); glutSpecialFunc(0); glutIdleFunc(0); glutReshapeFunc(0); // Release Framebuffers termProgs(); termFBO(); // Now we can destroy window glutDestroyWindow(idWindow); exit(0); } // Frame handler void display(void) { // Run benchmark CYCLES times if (++frames > CYCLES) {term();}; startBench(&frameBench); // Render animated texture startBench(&textureBench); renderFBO(); endBench(&textureBench); // Set up ModelView glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0,0.0,-5.0); glRotated(0.0,1.0,0.0,0.0); glRotated(rotY,0.0,1.0,0.0); rotY += incY; // Set attributes glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); // Clear render buffer and set teapot color glClearColor((float)0.2, (float)0.2, (float)0.2, (float)1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3d(0.9, 0.45, 0.0); // Render the teapot using our shader startBench(&teapotBench); glEnable(GL_VERTEX_PROGRAM_ARB); glEnable(GL_FRAGMENT_PROGRAM_ARB); glutSolidTeapot(1.0); glDisable(GL_FRAGMENT_PROGRAM_ARB); glDisable(GL_VERTEX_PROGRAM_ARB); endBench(&teapotBench); // Double-buffer and done glutSwapBuffers(); endBench(&frameBench); } // Keyboard handler void keyPressed(GLubyte key, GLint x, GLint y) { term(); } // Main app int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_ALPHA); glutInitWindowSize(windowWidth,windowHeight); idWindow = glutCreateWindow(PROGRAM); glutDisplayFunc(display); glutIdleFunc(display); //glutReshapeFunc(resizeScene); glutKeyboardFunc(keyPressed); init(); startBench(&appBench); glutMainLoop(); return(0); } Perl Binding

#!/usr/bin/perl -w # ogl_bench v1.0 - Copyright 2007 - Graphcomp # Bob Free bfree@graphcomp.com # http://graphcomp.com/opengl # This program is freely distributable without licensing fees # and is provided without guarantee or warrantee expressed or # implied. This program is -not- in the public domain. # Set up standard libs use strict; use Math::Trig; eval 'use Time::HiRes qw( gettimeofday )'; my $hasHires = !$@; # Only appBench will be valid if no HiRes sub ftime{return $hasHires ? gettimeofday() : time()} # Set up constants use constant PROGRAM => "OpenGL Benchmark - Perl Binding"; use constant CYCLES => 1000; # Setup OpenGL Extensions use OpenGL qw/ :all /; # Set up globals my $appBench = {}; my $frameBench = {}; my $textureBench = {}; my $teapotBench={}; my $now; my $frames = 0; my $idWindow = 0; my $windowWidth = 512; my $windowHeight = 512; my $textureWidth = 128; my $textureHeight = 128; my $rotTeapotX = 0; my $rotTeapotY = 0; my $idTexture = 0; my $idFrameBuffer = 0; my $idRenderBuffer = 0; my $idVertexProg = 0; my $idFragProg = 0; my $incY = 0.5; my $rotY = 0.0; # Start benchmark sub startBench { my($pBench) = @_; $pBench->{start} = ftime(); } # Accumulate benchmark sub endBench { my($pBench) = @_; $now = ftime(); $pBench->{secs} += $now - $pBench->{start}; } # Print benchmark sub printBench { my $overhead; if (!$frames || !$appBench->{secs} || !$frameBench->{secs} || !$textureBench->{secs} || !$teapotBench->{secs}) { printf("No measurable time has elapsed

"); return; } printf("FBO Texture Rendering FPS: %f

", $frames / $textureBench->{secs}); printf("Teapot Shader FPS: %f

", $frames / $teapotBench->{secs}); $overhead = $frameBench->{secs} - ($textureBench->{secs} + $teapotBench->{secs}); printf("Frame overhead secs/frame: %f

", $overhead / $frames); $overhead = $appBench->{secs} - $frameBench->{secs}; printf("OS/GLUT overhead secs/frame: %f

", $overhead / $frames); printf("Overall FPS: %f

", $frames / $appBench->{secs}); printf("

"); } # Error handling sub error { my($errTitle,$errMsg) = @_; printf("%s: %s

", $errTitle, $errMsg); exit(0); } # Check OpenGL Version sub checkVersion { my $version = glGetString(GL_VERSION); my $vendor = glGetString(GL_VENDOR); my $renderer = glGetString(GL_RENDERER); my $exts = glGetString(GL_EXTENSIONS); printf("%s



", PROGRAM); printf("OpenGL: %s

", $version); printf("Vendor: %s

", $vendor); printf("Renderer: %s

", $renderer); printf("

"); if ($exts !~ m|EXT_framebuffer_object|) { error("Extension not available","EXT_framebuffer_object"); } } # Initialize Vertex/Fragment Programs sub initProgs { # NOP Vertex shader my $vertexProg = qq {!!ARBvp1.0 TEMP vertexClip; DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position; DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position; DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position; DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position; MOV result.position, vertexClip; MOV result.color, vertex.color; MOV result.texcoord[0], vertex.texcoord; MOV result.texcoord[1], vertex.normal; END }; # Black Light Fragment shader my $fragProg = qq {!!ARBfp1.0 TEMP decal,color; TEX decal, fragment.texcoord[0], texture[0], 2D; MUL result.color, decal, fragment.texcoord[1]; END }; ($idVertexProg,$idFragProg) = glGenProgramsARB_p(2); glBindProgramARB(GL_VERTEX_PROGRAM_ARB, $idVertexProg); glProgramStringARB_p(GL_VERTEX_PROGRAM_ARB, $vertexProg); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, $idFragProg); glProgramStringARB_p(GL_FRAGMENT_PROGRAM_ARB, $fragProg); } # Terminate Vertex/Fragment Programs sub termProgs { glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); glDeleteProgramsARB_p($idVertexProg,$idFragProg); } # FBO Status handler sub statusFBO { my $stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (!$stat || $stat == GL_FRAMEBUFFER_COMPLETE_EXT) {return;}; printf("FBO status: %04X

", $stat); exit(0); } # Initialize Framebuffers sub initFBO { ($idTexture) = glGenTextures_p(1); ($idFrameBuffer) = glGenFramebuffersEXT_p(1); ($idRenderBuffer) = glGenRenderbuffersEXT_p(1); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, $idFrameBuffer); glBindTexture(GL_TEXTURE_2D, $idTexture); glTexImage2D_c(GL_TEXTURE_2D, 0, GL_RGBA8, $textureWidth, $textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, $idTexture, 0); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, $idRenderBuffer); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, $textureWidth, $textureHeight); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, $idRenderBuffer); statusFBO(); } # FBO texture renderer sub renderFBO { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, $idFrameBuffer); glLoadIdentity(); glTranslated(-0.75, -0.85, -2.5); glRotated($rotTeapotX, 1.0, 0.0, 0.0); $rotTeapotX += .5; glRotated($rotTeapotY, 0.0, 1.0, 0.0); $rotTeapotY += 1.0; glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3d(1.0, 1.0, 1.0); glutWireTeapot(0.125); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } # Terminate FBO objects sub termFBO { glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindTexture(GL_TEXTURE_2D, 0); glDeleteRenderbuffersEXT_p($idRenderBuffer); glDeleteFramebuffersEXT_p($idFrameBuffer); glDeleteTextures_p($idTexture); } # Resize Window sub resizeScene { my($width,$height) = @_; if (!$height){$height = 1;}; glViewport(0, 0, $width, $height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0,$width/$height,0.1,100.0); glMatrixMode(GL_MODELVIEW); $windowWidth = $width; $windowHeight = $height; } # Initialize OpenGL Environment sub init { checkVersion(); resizeScene($windowWidth, $windowHeight); initFBO(); initProgs(); } # Terminate OpenGL Environment sub term { # Display benchmark endBench($appBench); printBench(); # Disable app glutHideWindow(); glutKeyboardFunc(0); glutSpecialFunc(0); glutIdleFunc(0); glutReshapeFunc(0); # Release Framebuffers termProgs(); termFBO(); # Now we can destroy window glutDestroyWindow($idWindow); exit(0); } # Frame handler sub display { # Run benchmark CYCLES times if (++$frames > CYCLES) {term();}; startBench($frameBench); # Render animated texture startBench($textureBench); renderFBO(); endBench($textureBench); # Set up ModelView glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0,0.0,-5.0); glRotated(0.0,1.0,0.0,0.0); glRotated($rotY,0.0,1.0,0.0); $rotY += $incY; # Set attributes glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); # Clear render buffer and set teapot color glClearColor(0.2, 0.2, 0.2, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3d(0.9, 0.45, 0.0); # Render the teapot using our shader startBench($teapotBench); glEnable(GL_VERTEX_PROGRAM_ARB); glEnable(GL_FRAGMENT_PROGRAM_ARB); glutSolidTeapot(1.0); glDisable(GL_FRAGMENT_PROGRAM_ARB); glDisable(GL_VERTEX_PROGRAM_ARB); endBench($teapotBench); # Double-buffer and done glutSwapBuffers(); endBench($frameBench); } # Keyboard handler sub keyPressed { term(); } # Main app glutInit(@ARGV); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_ALPHA); glutInitWindowSize($windowWidth,$windowHeight); $idWindow = glutCreateWindow(PROGRAM); glutDisplayFunc(\&display); glutIdleFunc(\&display); #glutReshapeFunc(\&resizeScene); glutKeyboardFunc(\&keyPressed); init(); startBench($appBench); glutMainLoop(); exit(0); Note: Perl OpenGL (POGL) has no OS-dependencies; as such, you'll notice a bit of whitespace in the Perl code compared to C. POGL also provides additional Perl-ish OpenGL APIs (suffixed with "_p") to simplify string and array handling. While clearly there are differences between C and Perl, the similarities make it relatively easy to port code between the two. If you would like to add Java/Python/Ruby benchmarks to this comparison, please send the POGL team your port. Note : As of this writing, Java OpenGL (JOGL) does not support FBOs, but rather platform-specific pBuffers, which are known to have poorer performance than FBOs. Downloads This benchmark source and Win32/Linux binaries are available on this site Tarball

ZIP Review the README for build instructions.