| /* |
| * 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); |
| glBindBufferARB(GL_ARRAY_BUFFER_ARB, 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); |
| } |