/* * Copyright (C) 2009 VMware, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * Measure fill rates. * * Brian Paul * 21 Sep 2009 */ #include "glmain.h" #include "common.h" int WinWidth = 1000, WinHeight = 1000; static GLuint VBO, TexObj; struct vertex { GLfloat x, y, s, t, r, g, b, a; }; #define VOFFSET(F) ((void *) offsetof(struct vertex, F)) static const struct vertex vertices[4] = { /* x y s t r g b a */ { -1.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5 }, { 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.5 }, { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.5 }, { -1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.5 } }; static const char *VertexShader = "void main() \n" "{ \n" " gl_Position = ftransform(); \n" " gl_TexCoord[0] = gl_MultiTexCoord0; \n" " gl_FrontColor = gl_Color; \n" "} \n"; /* simple fragment shader */ static const char *FragmentShader1 = "uniform sampler2D Tex; \n" "void main() \n" "{ \n" " vec4 t = texture2D(Tex, gl_TexCoord[0].xy); \n" " gl_FragColor = vec4(1.0) - t * gl_Color; \n" "} \n"; /** * A more complex fragment shader (but equivalent to first shader). * A good optimizer should catch some of these no-op operations, but * probably not all of them. */ static const char *FragmentShader2 = "uniform sampler2D Tex; \n" "void main() \n" "{ \n" " // as above \n" " vec4 t = texture2D(Tex, gl_TexCoord[0].xy); \n" " t = vec4(1.0) - t * gl_Color; \n" " vec4 u; \n" " // no-op negate/swizzle \n" " u = -t.wzyx; \n" " t = -u.wzyx; \n" " // no-op inverts \n" " t = vec4(1.0) - t; \n" " t = vec4(1.0) - t; \n" " // no-op min/max \n" " t = min(t, t); \n" " t = max(t, t); \n" " // no-op moves \n" " u = t; \n" " t = u; \n" " u = t; \n" " t = u; \n" " // no-op add/mul \n" " t = (t + t + t + t) * 0.25; \n" " // no-op mul/sub \n" " t = 3.0 * t - 2.0 * t; \n" " // no-op negate/min/max \n" " t = -min(-t, -t); \n" " t = -max(-t, -t); \n" " gl_FragColor = t; \n" "} \n"; static GLuint ShaderProg1, ShaderProg2; /** Called from test harness/main */ void PerfInit(void) { GLint u; /* setup VBO w/ vertex data */ glGenBuffersARB(1, &VBO); glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO); glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices), vertices, GL_STATIC_DRAW_ARB); glVertexPointer(2, GL_FLOAT, sizeof(struct vertex), VOFFSET(x)); glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), VOFFSET(s)); glColorPointer(4, GL_FLOAT, sizeof(struct vertex), VOFFSET(r)); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); /* setup texture */ TexObj = PerfCheckerTexture(128, 128); /* setup shaders */ ShaderProg1 = PerfShaderProgram(VertexShader, FragmentShader1); glUseProgram(ShaderProg1); u = glGetUniformLocation(ShaderProg1, "Tex"); glUniform1i(u, 0); /* texture unit 0 */ ShaderProg2 = PerfShaderProgram(VertexShader, FragmentShader2); glUseProgram(ShaderProg2); u = glGetUniformLocation(ShaderProg2, "Tex"); glUniform1i(u, 0); /* texture unit 0 */ glUseProgram(0); } static void Ortho(void) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } static void DrawQuad(unsigned count) { unsigned i; glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < count; i++) { glDrawArrays(GL_TRIANGLE_FAN, 0, 4); /* Avoid sending command buffers with huge numbers of fullscreen * quads. Graphics schedulers don't always cope well with * this... */ if (i % 128 == 0) { PerfSwapBuffers(); glClear(GL_COLOR_BUFFER_BIT); } } glFinish(); if (1) PerfSwapBuffers(); } void PerfNextRound(void) { } /** Called from test harness/main */ void PerfDraw(void) { double rate; double pixelsPerDraw = WinWidth * WinHeight; Ortho(); /* simple fill */ rate = PerfMeasureRate(DrawQuad) * pixelsPerDraw; perf_printf(" Simple fill: %s pixels/second\n", PerfHumanFloat(rate)); /* blended fill */ glEnable(GL_BLEND); rate = PerfMeasureRate(DrawQuad) * pixelsPerDraw; glDisable(GL_BLEND); perf_printf(" Blended fill: %s pixels/second\n", PerfHumanFloat(rate)); /* textured fill */ glEnable(GL_TEXTURE_2D); glEnableClientState(GL_TEXTURE_COORD_ARRAY); rate = PerfMeasureRate(DrawQuad) * pixelsPerDraw; glDisable(GL_TEXTURE_2D); glDisableClientState(GL_TEXTURE_COORD_ARRAY); perf_printf(" Textured fill: %s pixels/second\n", PerfHumanFloat(rate)); /* shader1 fill */ glUseProgram(ShaderProg1); glEnableClientState(GL_TEXTURE_COORD_ARRAY); rate = PerfMeasureRate(DrawQuad) * pixelsPerDraw; glUseProgram(0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); perf_printf(" Shader1 fill: %s pixels/second\n", PerfHumanFloat(rate)); /* shader2 fill */ glUseProgram(ShaderProg2); glEnableClientState(GL_TEXTURE_COORD_ARRAY); rate = PerfMeasureRate(DrawQuad) * pixelsPerDraw; glUseProgram(0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); perf_printf(" Shader2 fill: %s pixels/second\n", PerfHumanFloat(rate)); exit(0); }