progs/perf: a few more vbo upload modes
authorKeith Whitwell <keithw@vmware.com>
Mon, 21 Sep 2009 14:56:17 +0000 (15:56 +0100)
committerKeith Whitwell <keithw@vmware.com>
Mon, 21 Sep 2009 14:57:14 +0000 (15:57 +0100)
Some tests, eg small SubData are probably overwhelmed by the cost of
performing the draw after each upload.  Add a varient which does a lot
of subdata uploads and then a single draw.

Also try to avoid cache-artifacts in the upload timings.

progs/perf/vbo.c

index d2630796ae29e3dc904b7c5d53b5703e0d087802..4b6e3f18746c4575bd7fdf96a3ec5dc035135a50 100644 (file)
 #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;
 
 static const GLboolean DrawPoint = GL_TRUE;
@@ -61,11 +65,23 @@ 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, GL_STREAM_DRAW_ARB);
+      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;
+      }
 
-      if (DrawPoint)
-         glDrawArrays(GL_POINTS, 0, 1);
+      src += VBOSize;
+      src %= DATA_SIZE;
    }
    glFinish();
 }
@@ -75,18 +91,42 @@ static void
 UploadSubVBO(unsigned count)
 {
    unsigned i;
+   unsigned src = 0;
+
    for (i = 0; i < count; i++) {
-      if (BufferSubDataInHalves) {
-         GLsizei half = VBOSize / 2;
-         glBufferSubDataARB(GL_ARRAY_BUFFER, 0, half, VBOData);
-         glBufferSubDataARB(GL_ARRAY_BUFFER, half, half, VBOData + half);
+      unsigned offset = (i * SubSize) % VBOSize;
+      glBufferSubDataARB(GL_ARRAY_BUFFER, offset, SubSize, VBOData + src);
+
+      if (DrawPoint) {
+         glDrawArrays(GL_POINTS, offset / sizeof(Vertex0), 1);
       }
-      else {
-         glBufferSubDataARB(GL_ARRAY_BUFFER, 0, VBOSize, VBOData);
+
+      src += SubSize;
+      src %= DATA_SIZE;
+   }
+   glFinish();
+}
+
+/* Do multiple small SubData uploads, the a 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);
       }
 
-      if (DrawPoint)
-         glDrawArrays(GL_POINTS, 0, 1);
+      glDrawArrays(GL_POINTS, 0, 1);
+
+      src += SubSize;
+      src %= DATA_SIZE;
    }
    glFinish();
 }
@@ -109,28 +149,61 @@ PerfDraw(void)
 {
    double rate, mbPerSec;
    int sub, sz;
+   int i;
+
+   VBOData = calloc(DATA_SIZE, 1);
+
+   for (i = 0; i < DATA_SIZE / sizeof(Vertex0); i++) {
+      memcpy(VBOData + i * sizeof(Vertex0), 
+             Vertex0, 
+             sizeof(Vertex0));
+   }
+
 
    /* loop over whole/sub buffer upload */
-   for (sub = 0; sub < 2; sub++) {
+   for (sub = 0; sub < 3; sub++) {
 
-      /* loop over VBO sizes */
-      for (sz = 0; Sizes[sz]; sz++) {
-         VBOSize = Sizes[sz];
+      if (sub == 2) {
+         VBOSize = 1024 * 1024;
 
-         VBOData = malloc(VBOSize);
-         memcpy(VBOData, Vertex0, sizeof(Vertex0));
+         glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData, GL_STREAM_DRAW_ARB);
 
-         if (sub)
+         for (sz = 0; Sizes[sz] < VBOSize; sz++) {
+            SubSize = Sizes[sz];
             rate = PerfMeasureRate(UploadSubVBO);
-         else
-            rate = PerfMeasureRate(UploadVBO);
 
-         mbPerSec = rate * VBOSize / (1024.0 * 1024.0);
+            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);
+         }
+      }
+      else {
+
+         /* loop over VBO sizes */
+         for (sz = 0; Sizes[sz]; sz++) {
+            SubSize = VBOSize = Sizes[sz];
+
+            if (sub == 1)
+               rate = PerfMeasureRate(UploadSubVBO);
+            else
+               rate = PerfMeasureRate(UploadVBO);
 
-         perf_printf("  glBuffer%sDataARB(size = %d): %.1f MB/sec\n",
-                     (sub ? "Sub" : ""), VBOSize, mbPerSec);
+            mbPerSec = rate * VBOSize / (1024.0 * 1024.0);
 
-         free(VBOData);
+            perf_printf("  glBuffer%sDataARB(size = %d): %.1f MB/sec\n",
+                        (sub ? "Sub" : ""), VBOSize, mbPerSec);
+         }
       }
    }