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