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 | 21 | ||||
| -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, 2500 insertions, 22 deletions
| diff --git a/progs/SConscript b/progs/SConscript index 620dd30e69..66eaf9e541 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 51435acfa0..a13339ea62 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 0df5ff09c3..20332b1d96 100644 --- a/progs/demos/cubemap.c +++ b/progs/demos/cubemap.c @@ -58,6 +58,9 @@ static GLint ClampIndex = 0;  static GLboolean supportFBO = GL_FALSE;  static GLboolean supportSeamless = GL_FALSE;  static GLboolean seamless = GL_FALSE; +static GLuint TexObj = 0; +static GLint T0 = 0; +static GLint Frames = 0;  static struct { @@ -282,6 +285,20 @@ static void draw( void )     glPopMatrix();     glutSwapBuffers(); + +   Frames++; + +   { +      GLint t = glutGet(GLUT_ELAPSED_TIME); +      if (t - T0 >= 5000) { +	 GLfloat seconds = (t - T0) / 1000.0; +	 GLfloat fps = Frames / seconds; +	 printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps); +	 fflush(stdout); +	 T0 = t; +	 Frames = 0; +      } +   }  } @@ -543,6 +560,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 30b1ed13d5..8d39bd605a 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 0000000000..2253efb085 --- /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 0000000000..5f04e9c76e --- /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 0000000000..cf7d359e78 --- /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 8103a5cbca..8928c833c0 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 0000000000..f078082685 --- /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 0000000000..acd6564e14 --- /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 0000000000..722f4b7b45 --- /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 0000000000..6ea17402b5 --- /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 0000000000..f7a6b8aec3 --- /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 0000000000..f75c9bb74e --- /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 0000000000..fb52a93a2f --- /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 0000000000..279f2b5f18 --- /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 0000000000..a167be042e --- /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 0000000000..d9bcd5f4e2 --- /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 0000000000..63c7fc06f9 --- /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 0000000000..a3005d0bef --- /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_FALSE; + +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 (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 0000000000..a9d4102de9 --- /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 0000000000..b5355525d0 --- /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 8839e10836..7dfed20cfb 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; | 
