diff options
Diffstat (limited to 'progs')
-rw-r--r-- | progs/SConscript | 1 | ||||
-rw-r--r-- | progs/demos/copypix.c | 22 | ||||
-rw-r--r-- | progs/demos/cubemap.c | 5 | ||||
-rw-r--r-- | progs/demos/lodbias.c | 4 | ||||
-rw-r--r-- | progs/fp/add-sat.txt | 6 | ||||
-rw-r--r-- | progs/fp/mov-alias.txt | 6 | ||||
-rw-r--r-- | progs/fp/mul-alias.txt | 6 | ||||
-rw-r--r-- | progs/glsl/Makefile | 17 | ||||
-rw-r--r-- | progs/perf/Makefile | 53 | ||||
-rw-r--r-- | progs/perf/SConscript | 30 | ||||
-rw-r--r-- | progs/perf/common.c | 133 | ||||
-rw-r--r-- | progs/perf/common.h | 44 | ||||
-rw-r--r-- | progs/perf/copytex.c | 214 | ||||
-rw-r--r-- | progs/perf/drawoverhead.c | 137 | ||||
-rw-r--r-- | progs/perf/fbobind.c | 153 | ||||
-rw-r--r-- | progs/perf/fill.c | 248 | ||||
-rw-r--r-- | progs/perf/glmain.c | 267 | ||||
-rw-r--r-- | progs/perf/glmain.h | 68 | ||||
-rw-r--r-- | progs/perf/swapbuffers.c | 161 | ||||
-rw-r--r-- | progs/perf/teximage.c | 331 | ||||
-rw-r--r-- | progs/perf/vbo.c | 245 | ||||
-rw-r--r-- | progs/perf/vertexrate.c | 276 | ||||
-rw-r--r-- | progs/tests/zreaddraw.c | 79 |
23 files changed, 2484 insertions, 22 deletions
diff --git a/progs/SConscript b/progs/SConscript index 620dd30e69c..66eaf9e5410 100644 --- a/progs/SConscript +++ b/progs/SConscript @@ -10,4 +10,5 @@ SConscript([ 'vpglsl/SConscript', 'fp/SConscript', 'wgl/SConscript', + 'perf/SConscript', ]) diff --git a/progs/demos/copypix.c b/progs/demos/copypix.c index 51435acfa0f..a13339ea62f 100644 --- a/progs/demos/copypix.c +++ b/progs/demos/copypix.c @@ -26,6 +26,7 @@ static int Scissor = 0; static float Xzoom, Yzoom; static GLboolean DrawFront = GL_FALSE; static GLboolean Dither = GL_TRUE; +static GLboolean Invert = GL_FALSE; static void Reset( void ) @@ -59,6 +60,15 @@ static void Display( void ) if (Scissor) glEnable(GL_SCISSOR_TEST); + if (Invert) { + glPixelTransferf(GL_RED_SCALE, -1.0); + glPixelTransferf(GL_GREEN_SCALE, -1.0); + glPixelTransferf(GL_BLUE_SCALE, -1.0); + glPixelTransferf(GL_RED_BIAS, 1.0); + glPixelTransferf(GL_GREEN_BIAS, 1.0); + glPixelTransferf(GL_BLUE_BIAS, 1.0); + } + /* draw copy */ glPixelZoom(Xzoom, Yzoom); glWindowPos2iARB(Xpos, Ypos); @@ -67,6 +77,15 @@ static void Display( void ) glDisable(GL_SCISSOR_TEST); + if (Invert) { + glPixelTransferf(GL_RED_SCALE, 1.0); + glPixelTransferf(GL_GREEN_SCALE, 1.0); + glPixelTransferf(GL_BLUE_SCALE, 1.0); + glPixelTransferf(GL_RED_BIAS, 0.0); + glPixelTransferf(GL_GREEN_BIAS, 0.0); + glPixelTransferf(GL_BLUE_BIAS, 0.0); + } + if (DrawFront) glFinish(); else @@ -105,6 +124,9 @@ static void Key( unsigned char key, int x, int y ) else glDisable(GL_DITHER); break; + case 'i': + Invert = !Invert; + break; case 's': Scissor = !Scissor; break; diff --git a/progs/demos/cubemap.c b/progs/demos/cubemap.c index 0df5ff09c33..015d50d86be 100644 --- a/progs/demos/cubemap.c +++ b/progs/demos/cubemap.c @@ -58,6 +58,7 @@ static GLint ClampIndex = 0; static GLboolean supportFBO = GL_FALSE; static GLboolean supportSeamless = GL_FALSE; static GLboolean seamless = GL_FALSE; +static GLuint TexObj = 0; static struct { @@ -543,6 +544,10 @@ static void init( GLboolean useImageFiles ) printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER)); + + glGenTextures(1, &TexObj); + glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, TexObj); + if (useImageFiles) { load_envmaps(); } diff --git a/progs/demos/lodbias.c b/progs/demos/lodbias.c index 30b1ed13d5f..8d39bd605a7 100644 --- a/progs/demos/lodbias.c +++ b/progs/demos/lodbias.c @@ -43,6 +43,7 @@ static GLboolean Anim = GL_TRUE; static GLint Bias = 0, BiasStepSign = +1; /* ints avoid fp precision problem */ static GLint BiasMin = -400, BiasMax = 400; static int win = 0; +static GLuint TexObj = 0; static void @@ -214,6 +215,9 @@ static void Init( void ) glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glGenTextures(1, &TexObj); + glBindTexture(GL_TEXTURE_2D, TexObj); + if (glutExtensionSupported("GL_SGIS_generate_mipmap")) { /* test auto mipmap generation */ GLint width, height, i; diff --git a/progs/fp/add-sat.txt b/progs/fp/add-sat.txt new file mode 100644 index 00000000000..2253efb0855 --- /dev/null +++ b/progs/fp/add-sat.txt @@ -0,0 +1,6 @@ +!!ARBfp1.0 +TEMP R0; +MOV R0, fragment.color; +ADD_SAT R0, R0, R0; +MUL result.color, {0.5}.x, R0; +END diff --git a/progs/fp/mov-alias.txt b/progs/fp/mov-alias.txt new file mode 100644 index 00000000000..5f04e9c76e2 --- /dev/null +++ b/progs/fp/mov-alias.txt @@ -0,0 +1,6 @@ +!!ARBfp1.0 +TEMP R0; +MOV R0, fragment.color; +MOV R0, R0.zyxw; +MOV result.color, R0; +END diff --git a/progs/fp/mul-alias.txt b/progs/fp/mul-alias.txt new file mode 100644 index 00000000000..cf7d359e780 --- /dev/null +++ b/progs/fp/mul-alias.txt @@ -0,0 +1,6 @@ +!!ARBfp1.0 +TEMP R0; +MOV R0, fragment.color; +MUL R0, R0.zyxw, fragment.color; +MOV result.color, R0; +END diff --git a/progs/glsl/Makefile b/progs/glsl/Makefile index 8103a5cbca0..8928c833c0e 100644 --- a/progs/glsl/Makefile +++ b/progs/glsl/Makefile @@ -10,16 +10,15 @@ LIB_DEP = \ $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) \ $(TOP)/$(LIB_DIR)/$(GLUT_LIB_NAME) -LIBS = -L$(TOP)/$(LIB_DIR) -l$(GLUT_LIB) -l$(GLEW_LIB) -l$(GLU_LIB) -l$(GL_LIB) $(APP_LIB_DEPS) - -INCLUDE_DIRS = -I$(TOP)/progs/util +LIBS = -L$(TOP)/$(LIB_DIR) -l$(GLUT_LIB) -l$(GLEW_LIB) -l$(GLU_LIB) \ + -l$(GL_LIB) $(APP_LIB_DEPS) # using : to avoid APP_CC pointing to CC loop -CC:=$(APP_CC) -CFLAGS += -I$(INCDIR) -LDLIBS=$(LIBS) +CC := $(APP_CC) +CFLAGS := -I$(INCDIR) $(CFLAGS) +LDLIBS = $(LIBS) -DEMO_SOURCES = \ +PROG_SOURCES = \ array.c \ bitmap.c \ brick.c \ @@ -59,8 +58,8 @@ UTIL_SOURCES = \ readtex.c UTIL_OBJS = $(UTIL_SOURCES:.c=.o) -PROG_OBJS = $(DEMO_SOURCES:.c=.o) -PROGS = $(DEMO_SOURCES:%.c=%) +PROG_OBJS = $(PROG_SOURCES:.c=.o) +PROGS = $(PROG_SOURCES:%.c=%) ##### TARGETS ##### diff --git a/progs/perf/Makefile b/progs/perf/Makefile new file mode 100644 index 00000000000..f078082685b --- /dev/null +++ b/progs/perf/Makefile @@ -0,0 +1,53 @@ +# progs/demos/Makefile + +TOP = ../.. +include $(TOP)/configs/current + +INCDIR = $(TOP)/include + +LIBS = -L$(TOP)/$(LIB_DIR) -l$(GLUT_LIB) -l$(GLEW_LIB) \ + -l$(GLU_LIB) -l$(GL_LIB) $(APP_LIB_DEPS) + +# using : to avoid APP_CC pointing to CC loop +CC := $(APP_CC) +CFLAGS += -I$(INCDIR) +LDLIBS = $(LIBS) + +PROG_SOURCES = \ + copytex.c \ + drawoverhead.c \ + fbobind.c \ + fill.c \ + swapbuffers.c \ + teximage.c \ + vbo.c \ + vertexrate.c \ + +PROG_OBJS = $(PROG_SOURCES:.c=.o) + +PROGS = $(PROG_SOURCES:%.c=%) + + +UTIL_SOURCES = \ + common.c \ + glmain.c + +UTIL_HEADERS = \ + common.h \ + glmain.h + +UTIL_OBJS = $(UTIL_SOURCES:.c=.o) + + + +default: $(PROGS) + +$(PROG_OBJS): $(UTIL_HEADERS) + +$(PROGS): $(UTIL_OBJS) + + + +clean: + -rm -f $(PROGS) + -rm -f *.o *~ diff --git a/progs/perf/SConscript b/progs/perf/SConscript new file mode 100644 index 00000000000..acd6564e14a --- /dev/null +++ b/progs/perf/SConscript @@ -0,0 +1,30 @@ +Import('env') + +if not env['GLUT']: + Return() + +env = env.Clone() + +env.Prepend(LIBS = ['$GLUT_LIB']) + +progs = [ + 'copytex', + 'drawoverhead', + 'fbobind', + 'fill', + 'teximage', + 'swapbuffers', + 'vbo', + 'vertexrate', +] + +for prog in progs: + env.Program( + target = prog, + source = [ + prog + '.c', + 'common.c', + 'glmain.c', + ] + ) + diff --git a/progs/perf/common.c b/progs/perf/common.c new file mode 100644 index 00000000000..722f4b7b454 --- /dev/null +++ b/progs/perf/common.c @@ -0,0 +1,133 @@ +/* + * 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. + */ + +/** + * Common perf code. This should be re-usable with other APIs. + */ + +#include "common.h" +#include "glmain.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + + +/* Need to add a fflush windows console with mingw, otherwise nothing + * shows up until program exit. May want to add logging here. + */ +void +perf_printf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + + fflush(stdout); + vfprintf(stdout, format, ap); + fflush(stdout); + + va_end(ap); +} + + + +/** + * Run function 'f' for enough iterations to reach a steady state. + * Return the rate (iterations/second). + */ +double +PerfMeasureRate(PerfRateFunc f) +{ + const double minDuration = 1.0; + double rate = 0.0, prevRate = 0.0; + unsigned subiters; + + /* Compute initial number of iterations to try. + * If the test function is pretty slow this helps to avoid + * extraordarily long run times. + */ + subiters = 2; + { + const double t0 = PerfGetTime(); + double t1; + do { + f(subiters); /* call the rendering function */ + t1 = PerfGetTime(); + subiters *= 2; + } while (t1 - t0 < 0.1 * minDuration); + } + /*perf_printf("initial subIters = %u\n", subiters);*/ + + while (1) { + const double t0 = PerfGetTime(); + unsigned iters = 0; + double t1; + + do { + f(subiters); /* call the rendering function */ + t1 = PerfGetTime(); + iters += subiters; + } while (t1 - t0 < minDuration); + + rate = iters / (t1 - t0); + + if (0) + perf_printf("prevRate %f rate %f ratio %f iters %u\n", + prevRate, rate, rate/prevRate, iters); + + /* Try and speed the search up by skipping a few steps: + */ + if (rate > prevRate * 1.6) + subiters *= 8; + else if (rate > prevRate * 1.2) + subiters *= 4; + else if (rate > prevRate * 1.05) + subiters *= 2; + else + break; + + prevRate = rate; + } + + if (0) + perf_printf("%s returning iters %u rate %f\n", __FUNCTION__, subiters, rate); + return rate; +} + + +/* Note static buffer, can only use once per printf. + */ +const char * +PerfHumanFloat( double d ) +{ + static char buf[80]; + + if (d > 1000000000.0) + snprintf(buf, sizeof(buf), "%.1f billion", d / 1000000000.0); + else if (d > 1000000.0) + snprintf(buf, sizeof(buf), "%.1f million", d / 1000000.0); + else if (d > 1000.0) + snprintf(buf, sizeof(buf), "%.1f thousand", d / 1000.0); + else + snprintf(buf, sizeof(buf), "%.1f", d); + + return buf; +} diff --git a/progs/perf/common.h b/progs/perf/common.h new file mode 100644 index 00000000000..6ea17402b52 --- /dev/null +++ b/progs/perf/common.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + + +#ifndef COMMON_H +#define COMMON_H + + +#include <stddef.h> /* for offsetof() */ + + +typedef void (*PerfRateFunc)(unsigned count); + + +extern double +PerfMeasureRate(PerfRateFunc f); + +const char * +PerfHumanFloat( double d ); + +extern void +perf_printf(const char *format, ...); + + +#endif /* COMMON_H */ + diff --git a/progs/perf/copytex.c b/progs/perf/copytex.c new file mode 100644 index 00000000000..f7a6b8aec39 --- /dev/null +++ b/progs/perf/copytex.c @@ -0,0 +1,214 @@ +/* + * 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 glCopyTex[Sub]Image() rate. + * Create a large, off-screen framebuffer object for rendering and + * copying the texture data from it since we can't make really large + * on-screen windows. + * + * Brian Paul + * 22 Sep 2009 + */ + +#include <string.h> +#include "glmain.h" +#include "common.h" + +int WinWidth = 100, WinHeight = 100; + +static GLuint VBO, FBO, RBO, Tex; + +const GLsizei MinSize = 16, MaxSize = 4096; +static GLsizei TexSize; + +static const GLboolean DrawPoint = GL_TRUE; +static const GLboolean TexSubImage4 = GL_FALSE; + +struct vertex +{ + GLfloat x, y, s, t; +}; + +static const struct vertex vertices[1] = { + { 0.0, 0.0, 0.5, 0.5 }, +}; + +#define VOFFSET(F) ((void *) offsetof(struct vertex, F)) + + +/** Called from test harness/main */ +void +PerfInit(void) +{ + const GLenum filter = GL_LINEAR; + GLenum stat; + + if (!PerfExtensionSupported("GL_EXT_framebuffer_object")) { + perf_printf("copytex: GL_EXT_framebuffer_object not supported\n"); + exit(0); + } + + /* setup VBO */ + 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)); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + /* setup texture */ + glGenTextures(1, &Tex); + glBindTexture(GL_TEXTURE_2D, Tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glEnable(GL_TEXTURE_2D); + + /* setup rbo */ + glGenRenderbuffersEXT(1, &RBO); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBO); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, MaxSize, MaxSize); + + /* setup fbo */ + glGenFramebuffersEXT(1, &FBO); + glBindFramebufferEXT(GL_FRAMEBUFFER, FBO); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, RBO); + + stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (stat != GL_FRAMEBUFFER_COMPLETE_EXT) { + perf_printf("fboswitch: Error: incomplete FBO!\n"); + exit(1); + } + + /* clear the FBO */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glViewport(0, 0, MaxSize, MaxSize); + glClear(GL_COLOR_BUFFER_BIT); +} + + +static void +CopyTexImage(unsigned count) +{ + unsigned i; + for (i = 1; i < count; i++) { + /* draw something */ + if (DrawPoint) + glDrawArrays(GL_POINTS, 0, 1); + + /* copy whole texture */ + glCopyTexImage2D(GL_TEXTURE_2D, 0, + GL_RGBA, 0, 0, TexSize, TexSize, 0); + } + glFinish(); +} + + +static void +CopyTexSubImage(unsigned count) +{ + unsigned i; + for (i = 1; i < count; i++) { + /* draw something */ + if (DrawPoint) + glDrawArrays(GL_POINTS, 0, 1); + + /* copy sub texture */ + if (TexSubImage4) { + /* four sub-copies */ + GLsizei half = TexSize / 2; + /* lower-left */ + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, 0, 0, half, half); + /* lower-right */ + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + half, 0, half, 0, half, half); + /* upper-left */ + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + 0, half, 0, half, half, half); + /* upper-right */ + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + half, half, half, half, half, half); + } + else { + /* one big copy */ + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, 0, 0, TexSize, TexSize); + } + } + glFinish(); +} + + +/** Called from test harness/main */ +void +PerfNextRound(void) +{ +} + + +/** Called from test harness/main */ +void +PerfDraw(void) +{ + double rate, mbPerSec; + GLint sub, maxTexSize; + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); + + /* loop over whole/sub tex copy */ + for (sub = 0; sub < 2; sub++) { + + /* loop over texture sizes */ + for (TexSize = MinSize; TexSize <= MaxSize; TexSize *= 4) { + + if (TexSize <= maxTexSize) { + GLint bytesPerImage = 4 * TexSize * TexSize; + + if (sub == 0) + rate = PerfMeasureRate(CopyTexImage); + else { + /* setup empty dest texture */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + TexSize, TexSize, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + rate = PerfMeasureRate(CopyTexSubImage); + } + + mbPerSec = rate * bytesPerImage / (1024.0 * 1024.0); + } + else { + rate = 0.0; + mbPerSec = 0.0; + } + + perf_printf(" glCopyTex%sImage(%d x %d): %.1f copies/sec, %.1f Mpixels/sec\n", + (sub ? "Sub" : ""), TexSize, TexSize, rate, mbPerSec); + } + } + + exit(0); +} diff --git a/progs/perf/drawoverhead.c b/progs/perf/drawoverhead.c new file mode 100644 index 00000000000..f75c9bb74e8 --- /dev/null +++ b/progs/perf/drawoverhead.c @@ -0,0 +1,137 @@ +/* + * 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 drawing overhead + * + * This is the first in a series of simple performance benchmarks. + * The code in this file should be as simple as possible to make it + * easily portable to other APIs. + * + * All the window-system stuff should be contained in glmain.c (or TBDmain.c). + * + * Brian Paul + * 15 Sep 2009 + */ + +#include "glmain.h" +#include "common.h" + + +int WinWidth = 100, WinHeight = 100; + +static GLuint VBO; + +struct vertex +{ + GLfloat x, y; +}; + +static const struct vertex vertices[4] = { + { -1.0, -1.0 }, + { 1.0, -1.0 }, + { 1.0, 1.0 }, + { -1.0, 1.0 } +}; + + +/** Called from test harness/main */ +void +PerfInit(void) +{ + /* 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), (void *) 0); + glEnableClientState(GL_VERTEX_ARRAY); + + /* misc GL state */ + glAlphaFunc(GL_ALWAYS, 0.0); +} + + +static void +DrawNoStateChange(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + glDrawArrays(GL_POINTS, 0, 4); + } + glFinish(); +} + + +static void +DrawNopStateChange(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + glDisable(GL_ALPHA_TEST); + glDrawArrays(GL_POINTS, 0, 4); + } + glFinish(); +} + + +static void +DrawStateChange(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + if (i & 1) + glEnable(GL_TEXTURE_GEN_S); + else + glDisable(GL_TEXTURE_GEN_S); + glDrawArrays(GL_POINTS, 0, 4); + } + glFinish(); +} + +void +PerfNextRound(void) +{ +} + +/** Called from test harness/main */ +void +PerfDraw(void) +{ + double rate0, rate1, rate2, overhead; + + rate0 = PerfMeasureRate(DrawNoStateChange); + perf_printf(" Draw only: %s draws/second\n", + PerfHumanFloat(rate0)); + + rate1 = PerfMeasureRate(DrawNopStateChange); + overhead = 1000.0 * (1.0 / rate1 - 1.0 / rate0); + perf_printf(" Draw w/ nop state change: %s draws/sec (overhead: %f ms/draw)\n", + PerfHumanFloat(rate1), overhead); + + rate2 = PerfMeasureRate(DrawStateChange); + overhead = 1000.0 * (1.0 / rate2 - 1.0 / rate0); + perf_printf(" Draw w/ state change: %s draws/sec (overhead: %f ms/draw)\n", + PerfHumanFloat(rate2), overhead); + + exit(0); +} + diff --git a/progs/perf/fbobind.c b/progs/perf/fbobind.c new file mode 100644 index 00000000000..fb52a93a2f6 --- /dev/null +++ b/progs/perf/fbobind.c @@ -0,0 +1,153 @@ +/* + * 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 rate of binding/switching between FBO targets. + * Create two framebuffer objects for rendering to two textures. + * Ping pong between texturing from one and drawing into the other. + * + * Brian Paul + * 22 Sep 2009 + */ + +#include <string.h> +#include "glmain.h" +#include "common.h" + +int WinWidth = 100, WinHeight = 100; + +static GLuint VBO; + +static GLuint FBO[2], Tex[2]; + +static const GLsizei TexSize = 512; + +static const GLboolean DrawPoint = GL_TRUE; + +struct vertex +{ + GLfloat x, y, s, t; +}; + +static const struct vertex vertices[1] = { + { 0.0, 0.0, 0.5, 0.5 }, +}; + +#define VOFFSET(F) ((void *) offsetof(struct vertex, F)) + + +/** Called from test harness/main */ +void +PerfInit(void) +{ + const GLenum filter = GL_LINEAR; + GLenum stat; + int i; + + if (!PerfExtensionSupported("GL_EXT_framebuffer_object")) { + perf_printf("fboswitch: GL_EXT_framebuffer_object not supported\n"); + exit(0); + } + + /* setup VBO */ + 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)); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glGenFramebuffersEXT(2, FBO); + glGenTextures(2, Tex); + + for (i = 0; i < 2; i++) { + /* setup texture */ + glBindTexture(GL_TEXTURE_2D, Tex[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + TexSize, TexSize, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + + + /* setup fbo */ + glBindFramebufferEXT(GL_FRAMEBUFFER, FBO[i]); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, Tex[i], 0/*level*/); + stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (stat != GL_FRAMEBUFFER_COMPLETE_EXT) { + perf_printf("fboswitch: Error: incomplete FBO!\n"); + exit(1); + } + + /* clear the FBO */ + glClear(GL_COLOR_BUFFER_BIT); + } + + glEnable(GL_TEXTURE_2D); +} + + +static void +FBOBind(unsigned count) +{ + unsigned i; + for (i = 1; i < count; i++) { + const GLuint dst = i & 1; + const GLuint src = 1 - dst; + + /* bind src texture */ + glBindTexture(GL_TEXTURE_2D, Tex[src]); + + /* bind dst fbo */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO[dst]); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + /* draw something */ + if (DrawPoint) + glDrawArrays(GL_POINTS, 0, 1); + } + glFinish(); +} + + +/** Called from test harness/main */ +void +PerfNextRound(void) +{ +} + + +/** Called from test harness/main */ +void +PerfDraw(void) +{ + double rate; + + rate = PerfMeasureRate(FBOBind); + perf_printf(" FBO Binding: %1.f binds/sec\n", rate); + + exit(0); +} diff --git a/progs/perf/fill.c b/progs/perf/fill.c new file mode 100644 index 00000000000..279f2b5f189 --- /dev/null +++ b/progs/perf/fill.c @@ -0,0 +1,248 @@ +/* + * 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); +} + diff --git a/progs/perf/glmain.c b/progs/perf/glmain.c new file mode 100644 index 00000000000..a167be042ef --- /dev/null +++ b/progs/perf/glmain.c @@ -0,0 +1,267 @@ +/* + * 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. + */ + +/** + * OpenGL/GLUT common code for perf programs. + * Brian Paul + * 15 Sep 2009 + */ + + +#include <stdio.h> +#include "glmain.h" +#include <GL/glut.h> + + +static int Win; +static GLfloat Xrot = 0, Yrot = 0, Zrot = 0; + + +/** Return time in seconds */ +double +PerfGetTime(void) +{ + return glutGet(GLUT_ELAPSED_TIME) * 0.001; +} + + +void +PerfSwapBuffers(void) +{ + glutSwapBuffers(); +} + + +/** make simple checkerboard texture object */ +GLuint +PerfCheckerTexture(GLsizei width, GLsizei height) +{ + const GLenum filter = GL_NEAREST; + GLubyte *img = (GLubyte *) malloc(width * height * 4); + GLint i, j, k; + GLuint obj; + + k = 0; + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + GLubyte color; + if (((i / 8) ^ (j / 8)) & 1) { + color = 0xff; + } + else { + color = 0x0; + } + img[k++] = color; + img[k++] = color; + img[k++] = color; + img[k++] = color; + } + } + + glGenTextures(1, &obj); + glBindTexture(GL_TEXTURE_2D, obj); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, img); + free(img); + + return obj; +} + + +static GLuint +CompileShader(GLenum type, const char *shader) +{ + GLuint sh; + GLint stat; + + sh = glCreateShader(type); + glShaderSource(sh, 1, (const GLchar **) &shader, NULL); + + glCompileShader(sh); + + glGetShaderiv(sh, GL_COMPILE_STATUS, &stat); + if (!stat) { + GLchar log[1000]; + GLsizei len; + glGetShaderInfoLog(sh, 1000, &len, log); + fprintf(stderr, "Error: problem compiling shader: %s\n", log); + exit(1); + } + + return sh; +} + + +/** Make shader program from given vert/frag shader text */ +GLuint +PerfShaderProgram(const char *vertShader, const char *fragShader) +{ + GLuint prog; + GLint stat; + + { + const char *version = (const char *) glGetString(GL_VERSION); + if (version[0] != '2' || version[1] != '.') { + fprintf(stderr, "Error: GL version 2.x required\n"); + exit(1); + } + } + + prog = glCreateProgram(); + + if (vertShader) { + GLuint vs = CompileShader(GL_VERTEX_SHADER, vertShader); + glAttachShader(prog, vs); + } + if (fragShader) { + GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragShader); + glAttachShader(prog, fs); + } + + glLinkProgram(prog); + glGetProgramiv(prog, GL_LINK_STATUS, &stat); + if (!stat) { + GLchar log[1000]; + GLsizei len; + glGetProgramInfoLog(prog, 1000, &len, log); + fprintf(stderr, "Shader link error:\n%s\n", log); + exit(1); + } + + return prog; +} + + +int +PerfReshapeWindow( unsigned w, unsigned h ) +{ + if (glutGet(GLUT_SCREEN_WIDTH) < w || + glutGet(GLUT_SCREEN_HEIGHT) < h) + return 0; + + glutReshapeWindow( w, h ); + glutPostRedisplay(); + return 1; +} + + +GLboolean +PerfExtensionSupported(const char *ext) +{ + return glutExtensionSupported(ext); +} + + +static void +Idle(void) +{ + PerfNextRound(); +} + + +static void +Draw(void) +{ + PerfDraw(); + glutSwapBuffers(); +} + + +static void +Reshape(int width, int height) +{ + WinWidth = width; + WinHeight = height; + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -15.0); +} + + +static void +Key(unsigned char key, int x, int y) +{ + const GLfloat step = 3.0; + (void) x; + (void) y; + switch (key) { + case 'z': + Zrot -= step; + break; + case 'Z': + Zrot += step; + break; + case 27: + glutDestroyWindow(Win); + exit(0); + break; + } + glutPostRedisplay(); +} + + +static void +SpecialKey(int key, int x, int y) +{ + const GLfloat step = 3.0; + (void) x; + (void) y; + switch (key) { + case GLUT_KEY_UP: + Xrot -= step; + break; + case GLUT_KEY_DOWN: + Xrot += step; + break; + case GLUT_KEY_LEFT: + Yrot -= step; + break; + case GLUT_KEY_RIGHT: + Yrot += step; + break; + } + glutPostRedisplay(); +} + + +int +main(int argc, char *argv[]) +{ + glutInit(&argc, argv); + glutInitWindowSize(WinWidth, WinHeight); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); + Win = glutCreateWindow(argv[0]); + glewInit(); + glutReshapeFunc(Reshape); + glutKeyboardFunc(Key); + glutSpecialFunc(SpecialKey); + glutDisplayFunc(Draw); + glutIdleFunc(Idle); + PerfInit(); + glutMainLoop(); + return 0; +} diff --git a/progs/perf/glmain.h b/progs/perf/glmain.h new file mode 100644 index 00000000000..d9bcd5f4e21 --- /dev/null +++ b/progs/perf/glmain.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + + +#ifndef GLMAIN_H +#define GLMAIN_H + + +#define GL_GLEXT_PROTOTYPES +#include <GL/glew.h> +#include <stdlib.h> +#include <math.h> + + +/** Test programs can use these vars/functions */ + +extern int WinWidth, WinHeight; + +extern double +PerfGetTime(void); + +extern void +PerfSwapBuffers(void); + +extern GLuint +PerfCheckerTexture(GLsizei width, GLsizei height); + +extern GLuint +PerfShaderProgram(const char *vertShader, const char *fragShader); + +extern int +PerfReshapeWindow( unsigned w, unsigned h ); + +extern GLboolean +PerfExtensionSupported(const char *ext); + + +/** Test programs must implement these functions **/ + +extern void +PerfInit(void); + +extern void +PerfNextRound(void); + +extern void +PerfDraw(void); + + +#endif /* GLMAIN_H */ diff --git a/progs/perf/swapbuffers.c b/progs/perf/swapbuffers.c new file mode 100644 index 00000000000..63c7fc06f98 --- /dev/null +++ b/progs/perf/swapbuffers.c @@ -0,0 +1,161 @@ +/* + * 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 SwapBuffers. + * + * Keith Whitwell + * 22 Sep 2009 + */ + +#include "glmain.h" +#include "common.h" + + +int WinWidth = 100, WinHeight = 100; +int real_WinWidth, real_WinHeight; /* don't know whats going on here */ + +static GLuint VBO; + +struct vertex +{ + GLfloat x, y; +}; + +static const struct vertex vertices[4] = { + { -1.0, -1.0 }, + { 1.0, -1.0 }, + { 1.0, 1.0 }, + { -1.0, 1.0 } +}; + + +/** Called from test harness/main */ +void +PerfInit(void) +{ + /* 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), (void *) 0); + glEnableClientState(GL_VERTEX_ARRAY); + + /* misc GL state */ + glAlphaFunc(GL_ALWAYS, 0.0); +} + +static void +SwapNaked(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + PerfSwapBuffers(); + } +} + + +static void +SwapClear(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + glClear(GL_COLOR_BUFFER_BIT); + PerfSwapBuffers(); + } +} + +static void +SwapClearPoint(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_POINTS, 0, 4); + PerfSwapBuffers(); + } +} + + +static const struct { + unsigned w; + unsigned h; +} sizes[] = { + { 320, 240 }, + { 640, 480 }, + { 1024, 768 }, + { 1200, 1024 }, + { 1600, 1200 } +}; + +void +PerfNextRound(void) +{ + static unsigned i; + + if (i < sizeof(sizes) / sizeof(sizes[0]) && + PerfReshapeWindow( sizes[i].w, sizes[i].h )) + { + perf_printf("Reshape %dx%d\n", sizes[i].w, sizes[i].h); + real_WinWidth = sizes[i].w; + real_WinHeight = sizes[i].h; + i++; + } + else { + exit(0); + } +} + + + + +/** Called from test harness/main */ +void +PerfDraw(void) +{ + double rate0; + + rate0 = PerfMeasureRate(SwapNaked); + perf_printf(" Swapbuffers %dx%d: %s swaps/second", + real_WinWidth, real_WinHeight, + PerfHumanFloat(rate0)); + perf_printf(" %s pixels/second\n", + PerfHumanFloat(rate0 * real_WinWidth * real_WinHeight)); + + + + rate0 = PerfMeasureRate(SwapClear); + perf_printf(" Swap/Clear %dx%d: %s swaps/second", + real_WinWidth, real_WinHeight, + PerfHumanFloat(rate0)); + perf_printf(" %s pixels/second\n", + PerfHumanFloat(rate0 * real_WinWidth * real_WinHeight)); + + + rate0 = PerfMeasureRate(SwapClearPoint); + perf_printf(" Swap/Clear/Draw %dx%d: %s swaps/second", + real_WinWidth, real_WinHeight, + PerfHumanFloat(rate0)); + perf_printf(" %s pixels/second\n", + PerfHumanFloat(rate0 * real_WinWidth * real_WinHeight)); +} + diff --git a/progs/perf/teximage.c b/progs/perf/teximage.c new file mode 100644 index 00000000000..0f41d349b75 --- /dev/null +++ b/progs/perf/teximage.c @@ -0,0 +1,331 @@ +/* + * 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 glTex[Sub]Image2D() and glGetTexImage() rate + * + * Brian Paul + * 16 Sep 2009 + */ + +#include "glmain.h" +#include "common.h" + + +int WinWidth = 100, WinHeight = 100; + +static GLuint VBO; +static GLuint TexObj = 0; +static GLubyte *TexImage = NULL; +static GLsizei TexSize; +static GLenum TexIntFormat, TexSrcFormat, TexSrcType; + +static const GLboolean DrawPoint = GL_TRUE; +static const GLboolean TexSubImage4 = GL_TRUE; + +enum { + MODE_CREATE_TEXIMAGE, + MODE_TEXIMAGE, + MODE_TEXSUBIMAGE, + MODE_GETTEXIMAGE, + MODE_COUNT +}; + +static const char *mode_name[MODE_COUNT] = +{ + "Create_TexImage", + "TexImage", + "TexSubImage", + "GetTexImage" +}; + + + +struct vertex +{ + GLfloat x, y, s, t; +}; + +static const struct vertex vertices[1] = { + { 0.0, 0.0, 0.5, 0.5 }, +}; + +#define VOFFSET(F) ((void *) offsetof(struct vertex, F)) + + +/** Called from test harness/main */ +void +PerfInit(void) +{ + /* 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)); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + /* texture */ + glGenTextures(1, &TexObj); + glBindTexture(GL_TEXTURE_2D, TexObj); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glEnable(GL_TEXTURE_2D); +} + + + + +static void +CreateUploadTexImage2D(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + if (TexObj) + glDeleteTextures(1, &TexObj); + + glGenTextures(1, &TexObj); + glBindTexture(GL_TEXTURE_2D, TexObj); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, + TexSize, TexSize, 0, + TexSrcFormat, TexSrcType, TexImage); + + if (DrawPoint) + glDrawArrays(GL_POINTS, 0, 1); + } + glFinish(); +} + + +static void +UploadTexImage2D(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + /* XXX is this equivalent to a glTexSubImage call since we're + * always specifying the same image size? That case isn't optimized + * in Mesa but may be optimized in other drivers. Note sure how + * much difference that might make. + */ + glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, + TexSize, TexSize, 0, + TexSrcFormat, TexSrcType, TexImage); + if (DrawPoint) + glDrawArrays(GL_POINTS, 0, 1); + } + glFinish(); +} + + +static void +UploadTexSubImage2D(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + if (0 && TexSubImage4) { + GLsizei halfSize = (TexSize == 1) ? 1 : TexSize / 2; + GLsizei halfPos = TexSize - halfSize; + /* do glTexSubImage2D in four pieces */ + /* lower-left */ + glPixelStorei(GL_UNPACK_ROW_LENGTH, TexSize); + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, halfSize, halfSize, + TexSrcFormat, TexSrcType, TexImage); + /* lower-right */ + glPixelStorei(GL_UNPACK_SKIP_PIXELS, halfPos); + glTexSubImage2D(GL_TEXTURE_2D, 0, + halfPos, 0, halfSize, halfSize, + TexSrcFormat, TexSrcType, TexImage); + /* upper-left */ + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, halfPos); + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, halfPos, halfSize, halfSize, + TexSrcFormat, TexSrcType, TexImage); + /* upper-right */ + glPixelStorei(GL_UNPACK_SKIP_PIXELS, halfPos); + glPixelStorei(GL_UNPACK_SKIP_ROWS, halfPos); + glTexSubImage2D(GL_TEXTURE_2D, 0, + halfPos, halfPos, halfSize, halfSize, + TexSrcFormat, TexSrcType, TexImage); + /* reset the unpacking state */ + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + else { + /* replace whole texture image at once */ + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, TexSize, TexSize, + TexSrcFormat, TexSrcType, TexImage); + } + if (DrawPoint) + glDrawArrays(GL_POINTS, 0, 1); + } + glFinish(); +} + + +static void +GetTexImage2D(unsigned count) +{ + unsigned i; + GLubyte *buf = (GLubyte *) malloc(TexSize * TexSize * 4); + for (i = 0; i < count; i++) { + glGetTexImage(GL_TEXTURE_2D, 0, + TexSrcFormat, TexSrcType, buf); + } + glFinish(); + free(buf); +} + + +/* XXX any other formats to measure? */ +static const struct { + GLenum format, type; + GLenum internal_format; + const char *name; + GLuint texel_size; + GLboolean full_test; +} SrcFormats[] = { + { GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, "RGBA/ubyte", 4, GL_TRUE }, + { GL_RGB, GL_UNSIGNED_BYTE, GL_RGB, "RGB/ubyte", 3, GL_FALSE }, + { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB, "RGB/565", 2, GL_FALSE }, + { GL_BGRA, GL_UNSIGNED_BYTE, GL_RGBA, "BGRA/ubyte", 4, GL_FALSE }, + { GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE, "L/ubyte", 1, GL_FALSE }, + { 0, 0, 0, NULL, 0, 0 } +}; + + +/** Called from test harness/main */ +void +PerfNextRound(void) +{ +} + + +/** Called from test harness/main */ +void +PerfDraw(void) +{ + GLint maxSize; + double rate; + GLint fmt, mode; + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); + + /* loop over source data formats */ + for (fmt = 0; SrcFormats[fmt].format; fmt++) { + TexIntFormat = SrcFormats[fmt].internal_format; + TexSrcFormat = SrcFormats[fmt].format; + TexSrcType = SrcFormats[fmt].type; + + /* loop over glTexImage, glTexSubImage */ + for (mode = 0; mode < MODE_COUNT; mode++) { + GLuint minsz, maxsz; + + if (SrcFormats[fmt].full_test) { + minsz = 16; + maxsz = 4096; + } + else { + minsz = maxsz = 256; + if (mode == MODE_CREATE_TEXIMAGE) + continue; + } + + /* loop over a defined range of texture sizes, test only the + * ones which are legal for this driver. + */ + for (TexSize = minsz; TexSize <= maxsz; TexSize *= 4) { + double mbPerSec; + + if (TexSize <= maxSize) { + GLint bytesPerImage; + + bytesPerImage = TexSize * TexSize * SrcFormats[fmt].texel_size; + TexImage = malloc(bytesPerImage); + + switch (mode) { + case MODE_TEXIMAGE: + rate = PerfMeasureRate(UploadTexImage2D); + break; + + case MODE_CREATE_TEXIMAGE: + rate = PerfMeasureRate(CreateUploadTexImage2D); + break; + + case MODE_TEXSUBIMAGE: + /* create initial, empty texture */ + glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, + TexSize, TexSize, 0, + TexSrcFormat, TexSrcType, NULL); + rate = PerfMeasureRate(UploadTexSubImage2D); + break; + + case MODE_GETTEXIMAGE: + glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, + TexSize, TexSize, 0, + TexSrcFormat, TexSrcType, TexImage); + rate = PerfMeasureRate(GetTexImage2D); + break; + + default: + exit(1); + } + + mbPerSec = rate * bytesPerImage / (1024.0 * 1024.0); + free(TexImage); + + + { + unsigned err; + err = glGetError(); + if (err) { + perf_printf("non-zero glGetError() %d\n", err); + exit(1); + } + } + + } + else { + rate = 0; + mbPerSec = 0; + } + + perf_printf(" %s(%s %d x %d): " + "%.1f images/sec, %.1f MB/sec\n", + mode_name[mode], + SrcFormats[fmt].name, TexSize, TexSize, rate, mbPerSec); + } + + if (SrcFormats[fmt].full_test) + perf_printf("\n"); + } + } + + exit(0); +} diff --git a/progs/perf/vbo.c b/progs/perf/vbo.c new file mode 100644 index 00000000000..a9d4102de9f --- /dev/null +++ b/progs/perf/vbo.c @@ -0,0 +1,245 @@ +/* + * 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 VBO upload speed. + * That is, measure glBufferDataARB() and glBufferSubDataARB(). + * + * Brian Paul + * 16 Sep 2009 + */ + +#include <string.h> +#include "glmain.h" +#include "common.h" + +/* Copy data out of a large array to avoid caching effects: + */ +#define DATA_SIZE (16*1024*1024) + +int WinWidth = 100, WinHeight = 100; + +static GLuint VBO; + +static GLsizei VBOSize = 0; +static GLsizei SubSize = 0; +static GLubyte *VBOData = NULL; /* array[DATA_SIZE] */ + +static const GLboolean DrawPoint = GL_TRUE; +static const GLboolean BufferSubDataInHalves = GL_TRUE; + +static const GLfloat Vertex0[2] = { 0.0, 0.0 }; + + +/** Called from test harness/main */ +void +PerfInit(void) +{ + /* setup VBO */ + glGenBuffersARB(1, &VBO); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO); + glVertexPointer(2, GL_FLOAT, sizeof(Vertex0), (void *) 0); + glEnableClientState(GL_VERTEX_ARRAY); +} + + +static void +UploadVBO(unsigned count) +{ + unsigned i; + unsigned total = 0; + unsigned src = 0; + + for (i = 0; i < count; i++) { + glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData + src, GL_STREAM_DRAW_ARB); + glDrawArrays(GL_POINTS, 0, 1); + + /* Throw in an occasional flush to work around a driver crash: + */ + total += VBOSize; + if (total >= 16*1024*1024) { + glFlush(); + total = 0; + } + + src += VBOSize; + src %= DATA_SIZE; + } + glFinish(); +} + + +static void +UploadSubVBO(unsigned count) +{ + unsigned i; + unsigned src = 0; + + for (i = 0; i < count; i++) { + unsigned offset = (i * SubSize) % VBOSize; + glBufferSubDataARB(GL_ARRAY_BUFFER, offset, SubSize, VBOData + src); + + if (DrawPoint) { + glDrawArrays(GL_POINTS, offset / sizeof(Vertex0), 1); + } + + src += SubSize; + src %= DATA_SIZE; + } + glFinish(); +} + + +/* Do multiple small SubData uploads, then call DrawArrays. This may be a + * fairer comparison to back-to-back BufferData calls: + */ +static void +BatchUploadSubVBO(unsigned count) +{ + unsigned i = 0, j; + unsigned period = VBOSize / SubSize; + unsigned src = 0; + + while (i < count) { + for (j = 0; j < period && i < count; j++, i++) { + unsigned offset = j * SubSize; + glBufferSubDataARB(GL_ARRAY_BUFFER, offset, SubSize, VBOData + src); + } + + glDrawArrays(GL_POINTS, 0, 1); + + src += SubSize; + src %= DATA_SIZE; + } + glFinish(); +} + + +/** + * Test the sequence: + * create/load VBO + * draw + * destroy VBO + */ +static void +CreateDrawDestroyVBO(unsigned count) +{ + unsigned i; + for (i = 0; i < count; i++) { + GLuint vbo; + /* create/load */ + glGenBuffersARB(1, &vbo); + glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData, GL_STREAM_DRAW_ARB); + /* draw */ + glVertexPointer(2, GL_FLOAT, sizeof(Vertex0), (void *) 0); + glDrawArrays(GL_POINTS, 0, 1); + /* destroy */ + glDeleteBuffersARB(1, &vbo); + } + glFinish(); +} + + +static const GLsizei Sizes[] = { + 64, + 1024, + 16*1024, + 256*1024, + 1024*1024, + 16*1024*1024, + 0 /* end of list */ +}; + +void +PerfNextRound(void) +{ +} + +/** Called from test harness/main */ +void +PerfDraw(void) +{ + double rate, mbPerSec; + int i, sz; + + /* Load VBOData buffer with duplicated Vertex0. + */ + VBOData = calloc(DATA_SIZE, 1); + + for (i = 0; i < DATA_SIZE / sizeof(Vertex0); i++) { + memcpy(VBOData + i * sizeof(Vertex0), + Vertex0, + sizeof(Vertex0)); + } + + /* glBufferDataARB() + */ + for (sz = 0; Sizes[sz]; sz++) { + SubSize = VBOSize = Sizes[sz]; + rate = PerfMeasureRate(UploadVBO); + mbPerSec = rate * VBOSize / (1024.0 * 1024.0); + perf_printf(" glBufferDataARB(size = %d): %.1f MB/sec\n", + VBOSize, mbPerSec); + } + + /* glBufferSubDataARB() + */ + for (sz = 0; Sizes[sz]; sz++) { + SubSize = VBOSize = Sizes[sz]; + rate = PerfMeasureRate(UploadSubVBO); + mbPerSec = rate * VBOSize / (1024.0 * 1024.0); + perf_printf(" glBufferSubDataARB(size = %d): %.1f MB/sec\n", + VBOSize, mbPerSec); + } + + /* Batch upload + */ + VBOSize = 1024 * 1024; + glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData, GL_STREAM_DRAW_ARB); + + for (sz = 0; Sizes[sz] < VBOSize; sz++) { + SubSize = Sizes[sz]; + rate = PerfMeasureRate(UploadSubVBO); + mbPerSec = rate * SubSize / (1024.0 * 1024.0); + perf_printf(" glBufferSubDataARB(size = %d, VBOSize = %d): %.1f MB/sec\n", + SubSize, VBOSize, mbPerSec); + } + + for (sz = 0; Sizes[sz] < VBOSize; sz++) { + SubSize = Sizes[sz]; + rate = PerfMeasureRate(BatchUploadSubVBO); + mbPerSec = rate * SubSize / (1024.0 * 1024.0); + perf_printf(" glBufferSubDataARB(size = %d, VBOSize = %d), batched: %.1f MB/sec\n", + SubSize, VBOSize, mbPerSec); + } + + /* Create/Draw/Destroy + */ + for (sz = 0; Sizes[sz]; sz++) { + SubSize = VBOSize = Sizes[sz]; + rate = PerfMeasureRate(CreateDrawDestroyVBO); + mbPerSec = rate * VBOSize / (1024.0 * 1024.0); + perf_printf(" VBO Create/Draw/Destroy(size = %d): %.1f MB/sec, %.1f draws/sec\n", + VBOSize, mbPerSec, rate); + } + + exit(0); +} diff --git a/progs/perf/vertexrate.c b/progs/perf/vertexrate.c new file mode 100644 index 00000000000..b5355525d06 --- /dev/null +++ b/progs/perf/vertexrate.c @@ -0,0 +1,276 @@ +/* + * 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 simple vertex processing rate via: + * - immediate mode + * - vertex arrays + * - VBO vertex arrays + * - glDrawElements + * - VBO glDrawElements + * - glDrawRangeElements + * - VBO glDrawRangeElements + * + * Brian Paul + * 16 Sep 2009 + */ + +#include <assert.h> +#include <string.h> +#include "glmain.h" +#include "common.h" + + +#define MAX_VERTS (100 * 100) + +/** glVertex2/3/4 size */ +#define VERT_SIZE 4 + +int WinWidth = 500, WinHeight = 500; + +static GLuint VertexBO, ElementBO; + +static unsigned NumVerts = MAX_VERTS; +static unsigned VertBytes = VERT_SIZE * sizeof(float); +static float *VertexData = NULL; + +static unsigned NumElements = MAX_VERTS; +static GLuint *Elements = NULL; + + +/** + * Load VertexData buffer with a 2-D grid of points in the range [-1,1]^2. + */ +static void +InitializeVertexData(void) +{ + unsigned i; + float x = -1.0, y = -1.0; + float dx = 2.0 / 100; + float dy = 2.0 / 100; + + VertexData = (float *) malloc(NumVerts * VertBytes); + + for (i = 0; i < NumVerts; i++) { + VertexData[i * VERT_SIZE + 0] = x; + VertexData[i * VERT_SIZE + 1] = y; + VertexData[i * VERT_SIZE + 2] = 0.0; + VertexData[i * VERT_SIZE + 3] = 1.0; + x += dx; + if (x > 1.0) { + x = -1.0; + y += dy; + } + } + + Elements = (GLuint *) malloc(NumVerts * sizeof(GLuint)); + + for (i = 0; i < NumVerts; i++) { + Elements[i] = NumVerts - i - 1; + } +} + + +/** Called from test harness/main */ +void +PerfInit(void) +{ + InitializeVertexData(); + + /* setup VertexBO */ + glGenBuffersARB(1, &VertexBO); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, VertexBO); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, + NumVerts * VertBytes, VertexData, GL_STATIC_DRAW_ARB); + glEnableClientState(GL_VERTEX_ARRAY); + + /* setup ElementBO */ + glGenBuffersARB(1, &ElementBO); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ElementBO); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + NumElements * sizeof(GLuint), Elements, GL_STATIC_DRAW_ARB); +} + + +static void +DrawImmediate(unsigned count) +{ + unsigned i; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBufferARB(GL_ARRAY_BUFFER, 0); + for (i = 0; i < count; i++) { + unsigned j; + glBegin(GL_POINTS); + for (j = 0; j < NumVerts; j++) { +#if VERT_SIZE == 4 + glVertex4fv(VertexData + j * 4); +#elif VERT_SIZE == 3 + glVertex3fv(VertexData + j * 3); +#elif VERT_SIZE == 2 + glVertex2fv(VertexData + j * 2); +#else + abort(); +#endif + } + glEnd(); + } + glFinish(); + PerfSwapBuffers(); +} + + +static void +DrawArraysMem(unsigned count) +{ + unsigned i; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBufferARB(GL_ARRAY_BUFFER, 0); + glVertexPointer(VERT_SIZE, GL_FLOAT, VertBytes, VertexData); + for (i = 0; i < count; i++) { + glDrawArrays(GL_POINTS, 0, NumVerts); + } + glFinish(); + PerfSwapBuffers(); +} + + +static void +DrawArraysVBO(unsigned count) +{ + unsigned i; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBufferARB(GL_ARRAY_BUFFER, VertexBO); + glVertexPointer(VERT_SIZE, GL_FLOAT, VertBytes, (void *) 0); + for (i = 0; i < count; i++) { + glDrawArrays(GL_POINTS, 0, NumVerts); + } + glFinish(); + PerfSwapBuffers(); +} + + +static void +DrawElementsMem(unsigned count) +{ + unsigned i; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBufferARB(GL_ARRAY_BUFFER, 0); + glVertexPointer(VERT_SIZE, GL_FLOAT, VertBytes, VertexData); + for (i = 0; i < count; i++) { + glDrawElements(GL_POINTS, NumVerts, GL_UNSIGNED_INT, Elements); + } + glFinish(); + PerfSwapBuffers(); +} + + +static void +DrawElementsBO(unsigned count) +{ + unsigned i; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, ElementBO); + glBindBufferARB(GL_ARRAY_BUFFER, VertexBO); + glVertexPointer(VERT_SIZE, GL_FLOAT, VertBytes, (void *) 0); + for (i = 0; i < count; i++) { + glDrawElements(GL_POINTS, NumVerts, GL_UNSIGNED_INT, (void *) 0); + } + glFinish(); + PerfSwapBuffers(); +} + + +static void +DrawRangeElementsMem(unsigned count) +{ + unsigned i; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBufferARB(GL_ARRAY_BUFFER, 0); + glVertexPointer(VERT_SIZE, GL_FLOAT, VertBytes, VertexData); + for (i = 0; i < count; i++) { + glDrawRangeElements(GL_POINTS, 0, NumVerts - 1, + NumVerts, GL_UNSIGNED_INT, Elements); + } + glFinish(); + PerfSwapBuffers(); +} + + +static void +DrawRangeElementsBO(unsigned count) +{ + unsigned i; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, ElementBO); + glBindBufferARB(GL_ARRAY_BUFFER, VertexBO); + glVertexPointer(VERT_SIZE, GL_FLOAT, VertBytes, (void *) 0); + for (i = 0; i < count; i++) { + glDrawRangeElements(GL_POINTS, 0, NumVerts - 1, + NumVerts, GL_UNSIGNED_INT, (void *) 0); + } + glFinish(); + PerfSwapBuffers(); +} + +void +PerfNextRound(void) +{ +} + + +/** Called from test harness/main */ +void +PerfDraw(void) +{ + double rate; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + perf_printf("Vertex rate (%d x Vertex%df)\n", NumVerts, VERT_SIZE); + + rate = PerfMeasureRate(DrawImmediate); + rate *= NumVerts; + perf_printf(" Immediate mode: %s verts/sec\n", PerfHumanFloat(rate)); + + rate = PerfMeasureRate(DrawArraysMem); + rate *= NumVerts; + perf_printf(" glDrawArrays: %s verts/sec\n", PerfHumanFloat(rate)); + + rate = PerfMeasureRate(DrawArraysVBO); + rate *= NumVerts; + perf_printf(" VBO glDrawArrays: %s verts/sec\n", PerfHumanFloat(rate)); + + rate = PerfMeasureRate(DrawElementsMem); + rate *= NumVerts; + perf_printf(" glDrawElements: %s verts/sec\n", PerfHumanFloat(rate)); + + rate = PerfMeasureRate(DrawElementsBO); + rate *= NumVerts; + perf_printf(" VBO glDrawElements: %s verts/sec\n", PerfHumanFloat(rate)); + + rate = PerfMeasureRate(DrawRangeElementsMem); + rate *= NumVerts; + perf_printf(" glDrawRangeElements: %s verts/sec\n", PerfHumanFloat(rate)); + + rate = PerfMeasureRate(DrawRangeElementsBO); + rate *= NumVerts; + perf_printf(" VBO glDrawRangeElements: %s verts/sec\n", PerfHumanFloat(rate)); + + exit(0); +} diff --git a/progs/tests/zreaddraw.c b/progs/tests/zreaddraw.c index 8839e108360..7dfed20cfb9 100644 --- a/progs/tests/zreaddraw.c +++ b/progs/tests/zreaddraw.c @@ -12,14 +12,17 @@ #include <GL/glut.h> static GLint WinWidth = 500, WinHeight = 500; +static GLboolean Invert = GL_FALSE; +static GLboolean TestPacking = GL_FALSE; +static GLboolean TestList = GL_FALSE; static void Display(void) { - GLfloat depth[100 * 100]; - GLfloat depth2[400 * 400]; - GLfloat min, max; - int i; + GLfloat depth[100 * 100 * 2]; + GLfloat depth2[400 * 400]; /* *2 to test pixelstore stuff */ + GLuint list; + GLenum depthType = GL_FLOAT; glClearColor(0.5, 0.5, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -35,22 +38,61 @@ static void Display(void) glLoadIdentity(); glutSolidSphere(1.0, 20, 10); + if (TestPacking) { + glPixelStorei(GL_PACK_ROW_LENGTH, 120); + glPixelStorei(GL_PACK_SKIP_PIXELS, 5); + } + /* read the depth image */ - glReadPixels(0, 0, 100, 100, GL_DEPTH_COMPONENT, GL_FLOAT, depth); - min = max = depth[0]; - for (i = 1; i < 100 * 100; i++) { - if (depth[i] < min) - min = depth[i]; - if (depth[i] > max) - max = depth[i]; + glReadPixels(0, 0, 100, 100, GL_DEPTH_COMPONENT, depthType, depth); + if (depthType == GL_FLOAT) { + GLfloat min, max; + int i; + min = max = depth[0]; + for (i = 1; i < 100 * 100; i++) { + if (depth[i] < min) + min = depth[i]; + if (depth[i] > max) + max = depth[i]; + } + printf("Depth value range: [%f, %f]\n", min, max); + } + + if (TestPacking) { + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 120); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 5); } - printf("Depth value range: [%f, %f]\n", min, max); /* draw depth image with scaling (into z buffer) */ glPixelZoom(4.0, 4.0); glColor4f(1, 0, 0, 0); glWindowPos2i(100, 0); - glDrawPixels(100, 100, GL_DEPTH_COMPONENT, GL_FLOAT, depth); + if (Invert) { + glPixelTransferf(GL_DEPTH_SCALE, -1.0); + glPixelTransferf(GL_DEPTH_BIAS, 1.0); + } + if (TestList) { + list = glGenLists(1); + glNewList(list, GL_COMPILE); + glDrawPixels(100, 100, GL_DEPTH_COMPONENT, depthType, depth); + glEndList(); + glCallList(list); + glDeleteLists(list, 1); + } + else { + glDrawPixels(100, 100, GL_DEPTH_COMPONENT, depthType, depth); + } + if (Invert) { + glPixelTransferf(GL_DEPTH_SCALE, 1.0); + glPixelTransferf(GL_DEPTH_BIAS, 0.0); + } + + if (TestPacking) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + } glDisable(GL_DEPTH_TEST); @@ -77,6 +119,17 @@ static void Key(unsigned char key, int x, int y) (void) x; (void) y; switch (key) { + case 'i': + Invert = !Invert; + break; + case 'p': + TestPacking = !TestPacking; + printf("Test pixel pack/unpack: %d\n", TestPacking); + break; + case 'l': + TestList = !TestList; + printf("Test dlist: %d\n", TestList); + break; case 27: exit(0); break; |