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 
38 int WinWidth = 100, WinHeight = 100;
39 
40 static GLuint VBO;
41 
42 static GLsizei VBOSize = 0;
43 static GLsizei SubSize = 0;
44 static GLubyte *VBOData = NULL;  /* array[DATA_SIZE] */
45 
46 static const GLboolean DrawPoint = GL_TRUE;
47 static const GLboolean BufferSubDataInHalves = GL_TRUE;
48 
49 static const GLfloat Vertex0[2] = { 0.0, 0.0 };
50 
51 
52 /** Called from test harness/main */
53 void
PerfInit(void)54 PerfInit(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 
64 static void
UploadVBO(unsigned count)65 UploadVBO(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 
90 static void
UploadSubVBO(unsigned count)91 UploadSubVBO(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  */
114 static void
BatchUploadSubVBO(unsigned count)115 BatchUploadSubVBO(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  */
142 static void
CreateDrawDestroyVBO(unsigned count)143 CreateDrawDestroyVBO(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 
162 static 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 
172 void
PerfNextRound(void)173 PerfNextRound(void)
174 {
175 }
176 
177 /** Called from test harness/main */
178 void
PerfDraw(void)179 PerfDraw(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