#!/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\n"); return; } printf("FBO Texture Rendering FPS: %f\n", $frames / $textureBench->{secs}); printf("Teapot Shader FPS: %f\n", $frames / $teapotBench->{secs}); $overhead = $frameBench->{secs} - ($textureBench->{secs} + $teapotBench->{secs}); printf("Frame overhead secs/frame: %f\n", $overhead / $frames); $overhead = $appBench->{secs} - $frameBench->{secs}; printf("OS/GLUT overhead secs/frame: %f\n", $overhead / $frames); printf("Overall FPS: %f\n", $frames / $appBench->{secs}); printf("\n"); } # Error handling sub error { my($errTitle,$errMsg) = @_; printf("%s: %s\n", $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\n\n", PROGRAM); printf("OpenGL: %s\n", $version); printf("Vendor: %s\n", $vendor); printf("Renderer: %s\n", $renderer); printf("\n"); 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\n", $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);