vbo.c revision 32001f49
1/*
2 * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22/**
23 * Measure VBO upload speed.
24 * That is, measure glBufferDataARB() and glBufferSubDataARB().
25 *
26 * Brian Paul
27 * 16 Sep 2009
28 */
29
30#include <string.h>
31#include "glmain.h"
32#include "common.h"
33
34/* Copy data out of a large array to avoid caching effects:
35 */
36#define DATA_SIZE (16*1024*1024)
37
38int WinWidth = 100, WinHeight = 100;
39
40static GLuint VBO;
41
42static GLsizei VBOSize = 0;
43static GLsizei SubSize = 0;
44static GLubyte *VBOData = NULL;  /* array[DATA_SIZE] */
45
46static const GLboolean DrawPoint = GL_TRUE;
47static const GLboolean BufferSubDataInHalves = GL_TRUE;
48
49static const GLfloat Vertex0[2] = { 0.0, 0.0 };
50
51
52/** Called from test harness/main */
53void
54PerfInit(void)
55{
56   /* setup VBO */
57   glGenBuffersARB(1, &VBO);
58   glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO);
59   glVertexPointer(2, GL_FLOAT, sizeof(Vertex0), (void *) 0);
60   glEnableClientState(GL_VERTEX_ARRAY);
61}
62
63
64static void
65UploadVBO(unsigned count)
66{
67   unsigned i;
68   unsigned total = 0;
69   unsigned src = 0;
70
71   for (i = 0; i < count; i++) {
72      glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData + src, GL_STREAM_DRAW_ARB);
73      glDrawArrays(GL_POINTS, 0, 1);
74
75      /* Throw in an occasional flush to work around a driver crash:
76       */
77      total += VBOSize;
78      if (total >= 16*1024*1024) {
79         glFlush();
80         total = 0;
81      }
82
83      src += VBOSize;
84      src %= DATA_SIZE;
85   }
86   glFinish();
87}
88
89
90static void
91UploadSubVBO(unsigned count)
92{
93   unsigned i;
94   unsigned src = 0;
95
96   for (i = 0; i < count; i++) {
97      unsigned offset = (i * SubSize) % VBOSize;
98      glBufferSubDataARB(GL_ARRAY_BUFFER, offset, SubSize, VBOData + src);
99
100      if (DrawPoint) {
101         glDrawArrays(GL_POINTS, offset / sizeof(Vertex0), 1);
102      }
103
104      src += SubSize;
105      src %= DATA_SIZE;
106   }
107   glFinish();
108}
109
110
111/* Do multiple small SubData uploads, then call DrawArrays.  This may be a
112 * fairer comparison to back-to-back BufferData calls:
113 */
114static void
115BatchUploadSubVBO(unsigned count)
116{
117   unsigned i = 0, j;
118   unsigned period = VBOSize / SubSize;
119   unsigned src = 0;
120
121   while (i < count) {
122      for (j = 0; j < period && i < count; j++, i++) {
123         unsigned offset = j * SubSize;
124         glBufferSubDataARB(GL_ARRAY_BUFFER, offset, SubSize, VBOData + src);
125      }
126
127      glDrawArrays(GL_POINTS, 0, 1);
128
129      src += SubSize;
130      src %= DATA_SIZE;
131   }
132   glFinish();
133}
134
135
136/**
137 * Test the sequence:
138 *    create/load VBO
139 *    draw
140 *    destroy VBO
141 */
142static void
143CreateDrawDestroyVBO(unsigned count)
144{
145   unsigned i;
146   for (i = 0; i < count; i++) {
147      GLuint vbo;
148      /* create/load */
149      glGenBuffersARB(1, &vbo);
150      glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo);
151      glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData, GL_STREAM_DRAW_ARB);
152      /* draw */
153      glVertexPointer(2, GL_FLOAT, sizeof(Vertex0), (void *) 0);
154      glDrawArrays(GL_POINTS, 0, 1);
155      /* destroy */
156      glDeleteBuffersARB(1, &vbo);
157   }
158   glFinish();
159}
160
161
162static const GLsizei Sizes[] = {
163   64,
164   1024,
165   16*1024,
166   256*1024,
167   1024*1024,
168   16*1024*1024,
169   0 /* end of list */
170};
171
172void
173PerfNextRound(void)
174{
175}
176
177/** Called from test harness/main */
178void
179PerfDraw(void)
180{
181   double rate, mbPerSec;
182   int i, sz;
183
184   /* Load VBOData buffer with duplicated Vertex0.
185    */
186   VBOData = calloc(DATA_SIZE, 1);
187
188   for (i = 0; i < DATA_SIZE / sizeof(Vertex0); i++) {
189      memcpy(VBOData + i * sizeof(Vertex0),
190             Vertex0,
191             sizeof(Vertex0));
192   }
193
194   /* glBufferDataARB()
195    */
196   for (sz = 0; Sizes[sz]; sz++) {
197      SubSize = VBOSize = Sizes[sz];
198      rate = PerfMeasureRate(UploadVBO);
199      mbPerSec = rate * VBOSize / (1024.0 * 1024.0);
200      perf_printf("  glBufferDataARB(size = %d): %.1f MB/sec\n",
201                  VBOSize, mbPerSec);
202   }
203
204   /* glBufferSubDataARB()
205    */
206   for (sz = 0; Sizes[sz]; sz++) {
207      SubSize = VBOSize = Sizes[sz];
208      rate = PerfMeasureRate(UploadSubVBO);
209      mbPerSec = rate * VBOSize / (1024.0 * 1024.0);
210      perf_printf("  glBufferSubDataARB(size = %d): %.1f MB/sec\n",
211                  VBOSize, mbPerSec);
212   }
213
214   /* Batch upload
215    */
216   VBOSize = 1024 * 1024;
217   glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData, GL_STREAM_DRAW_ARB);
218
219   for (sz = 0; Sizes[sz] < VBOSize; sz++) {
220      SubSize = Sizes[sz];
221      rate = PerfMeasureRate(UploadSubVBO);
222      mbPerSec = rate * SubSize / (1024.0 * 1024.0);
223      perf_printf("  glBufferSubDataARB(size = %d, VBOSize = %d): %.1f MB/sec\n",
224                  SubSize, VBOSize, mbPerSec);
225   }
226
227   for (sz = 0; Sizes[sz] < VBOSize; sz++) {
228      SubSize = Sizes[sz];
229      rate = PerfMeasureRate(BatchUploadSubVBO);
230      mbPerSec = rate * SubSize / (1024.0 * 1024.0);
231      perf_printf("  glBufferSubDataARB(size = %d, VBOSize = %d), batched: %.1f MB/sec\n",
232                  SubSize, VBOSize, mbPerSec);
233   }
234
235   /* Create/Draw/Destroy
236    */
237   for (sz = 0; Sizes[sz]; sz++) {
238      SubSize = VBOSize = Sizes[sz];
239      rate = PerfMeasureRate(CreateDrawDestroyVBO);
240      mbPerSec = rate * VBOSize / (1024.0 * 1024.0);
241      perf_printf("  VBO Create/Draw/Destroy(size = %d): %.1f MB/sec, %.1f draws/sec\n",
242                  VBOSize, mbPerSec, rate);
243   }
244
245   exit(0);
246}
247