132001f49Smrg/* 232001f49Smrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 332001f49Smrg * 432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a 532001f49Smrg * copy of this software and associated documentation files (the "Software"), 632001f49Smrg * to deal in the Software without restriction, including without limitation 732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the 932001f49Smrg * Software is furnished to do so, subject to the following conditions: 1032001f49Smrg * 1132001f49Smrg * The above copyright notice and this permission notice shall be included 1232001f49Smrg * in all copies or substantial portions of the Software. 1332001f49Smrg * 1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1532001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1732001f49Smrg * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1832001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1932001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2032001f49Smrg */ 2132001f49Smrg 2232001f49Smrg/** 2332001f49Smrg * Measure VBO upload speed. 2432001f49Smrg * That is, measure glBufferDataARB() and glBufferSubDataARB(). 2532001f49Smrg * 2632001f49Smrg * Brian Paul 2732001f49Smrg * 16 Sep 2009 2832001f49Smrg */ 2932001f49Smrg 3032001f49Smrg#include <string.h> 3132001f49Smrg#include "glmain.h" 3232001f49Smrg#include "common.h" 3332001f49Smrg 3432001f49Smrg/* Copy data out of a large array to avoid caching effects: 3532001f49Smrg */ 3632001f49Smrg#define DATA_SIZE (16*1024*1024) 3732001f49Smrg 3832001f49Smrgint WinWidth = 100, WinHeight = 100; 3932001f49Smrg 4032001f49Smrgstatic GLuint VBO; 4132001f49Smrg 4232001f49Smrgstatic GLsizei VBOSize = 0; 4332001f49Smrgstatic GLsizei SubSize = 0; 4432001f49Smrgstatic GLubyte *VBOData = NULL; /* array[DATA_SIZE] */ 4532001f49Smrg 4632001f49Smrgstatic const GLboolean DrawPoint = GL_TRUE; 4732001f49Smrgstatic const GLboolean BufferSubDataInHalves = GL_TRUE; 4832001f49Smrg 4932001f49Smrgstatic const GLfloat Vertex0[2] = { 0.0, 0.0 }; 5032001f49Smrg 5132001f49Smrg 5232001f49Smrg/** Called from test harness/main */ 5332001f49Smrgvoid 5432001f49SmrgPerfInit(void) 5532001f49Smrg{ 5632001f49Smrg /* setup VBO */ 5732001f49Smrg glGenBuffersARB(1, &VBO); 5832001f49Smrg glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO); 5932001f49Smrg glVertexPointer(2, GL_FLOAT, sizeof(Vertex0), (void *) 0); 6032001f49Smrg glEnableClientState(GL_VERTEX_ARRAY); 6132001f49Smrg} 6232001f49Smrg 6332001f49Smrg 6432001f49Smrgstatic void 6532001f49SmrgUploadVBO(unsigned count) 6632001f49Smrg{ 6732001f49Smrg unsigned i; 6832001f49Smrg unsigned total = 0; 6932001f49Smrg unsigned src = 0; 7032001f49Smrg 7132001f49Smrg for (i = 0; i < count; i++) { 7232001f49Smrg glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData + src, GL_STREAM_DRAW_ARB); 7332001f49Smrg glDrawArrays(GL_POINTS, 0, 1); 7432001f49Smrg 7532001f49Smrg /* Throw in an occasional flush to work around a driver crash: 7632001f49Smrg */ 7732001f49Smrg total += VBOSize; 7832001f49Smrg if (total >= 16*1024*1024) { 7932001f49Smrg glFlush(); 8032001f49Smrg total = 0; 8132001f49Smrg } 8232001f49Smrg 8332001f49Smrg src += VBOSize; 8432001f49Smrg src %= DATA_SIZE; 8532001f49Smrg } 8632001f49Smrg glFinish(); 8732001f49Smrg} 8832001f49Smrg 8932001f49Smrg 9032001f49Smrgstatic void 9132001f49SmrgUploadSubVBO(unsigned count) 9232001f49Smrg{ 9332001f49Smrg unsigned i; 9432001f49Smrg unsigned src = 0; 9532001f49Smrg 9632001f49Smrg for (i = 0; i < count; i++) { 9732001f49Smrg unsigned offset = (i * SubSize) % VBOSize; 9832001f49Smrg glBufferSubDataARB(GL_ARRAY_BUFFER, offset, SubSize, VBOData + src); 9932001f49Smrg 10032001f49Smrg if (DrawPoint) { 10132001f49Smrg glDrawArrays(GL_POINTS, offset / sizeof(Vertex0), 1); 10232001f49Smrg } 10332001f49Smrg 10432001f49Smrg src += SubSize; 10532001f49Smrg src %= DATA_SIZE; 10632001f49Smrg } 10732001f49Smrg glFinish(); 10832001f49Smrg} 10932001f49Smrg 11032001f49Smrg 11132001f49Smrg/* Do multiple small SubData uploads, then call DrawArrays. This may be a 11232001f49Smrg * fairer comparison to back-to-back BufferData calls: 11332001f49Smrg */ 11432001f49Smrgstatic void 11532001f49SmrgBatchUploadSubVBO(unsigned count) 11632001f49Smrg{ 11732001f49Smrg unsigned i = 0, j; 11832001f49Smrg unsigned period = VBOSize / SubSize; 11932001f49Smrg unsigned src = 0; 12032001f49Smrg 12132001f49Smrg while (i < count) { 12232001f49Smrg for (j = 0; j < period && i < count; j++, i++) { 12332001f49Smrg unsigned offset = j * SubSize; 12432001f49Smrg glBufferSubDataARB(GL_ARRAY_BUFFER, offset, SubSize, VBOData + src); 12532001f49Smrg } 12632001f49Smrg 12732001f49Smrg glDrawArrays(GL_POINTS, 0, 1); 12832001f49Smrg 12932001f49Smrg src += SubSize; 13032001f49Smrg src %= DATA_SIZE; 13132001f49Smrg } 13232001f49Smrg glFinish(); 13332001f49Smrg} 13432001f49Smrg 13532001f49Smrg 13632001f49Smrg/** 13732001f49Smrg * Test the sequence: 13832001f49Smrg * create/load VBO 13932001f49Smrg * draw 14032001f49Smrg * destroy VBO 14132001f49Smrg */ 14232001f49Smrgstatic void 14332001f49SmrgCreateDrawDestroyVBO(unsigned count) 14432001f49Smrg{ 14532001f49Smrg unsigned i; 14632001f49Smrg for (i = 0; i < count; i++) { 14732001f49Smrg GLuint vbo; 14832001f49Smrg /* create/load */ 14932001f49Smrg glGenBuffersARB(1, &vbo); 15032001f49Smrg glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo); 15132001f49Smrg glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData, GL_STREAM_DRAW_ARB); 15232001f49Smrg /* draw */ 15332001f49Smrg glVertexPointer(2, GL_FLOAT, sizeof(Vertex0), (void *) 0); 15432001f49Smrg glDrawArrays(GL_POINTS, 0, 1); 15532001f49Smrg /* destroy */ 15632001f49Smrg glDeleteBuffersARB(1, &vbo); 15732001f49Smrg } 15832001f49Smrg glFinish(); 15932001f49Smrg} 16032001f49Smrg 16132001f49Smrg 16232001f49Smrgstatic const GLsizei Sizes[] = { 16332001f49Smrg 64, 16432001f49Smrg 1024, 16532001f49Smrg 16*1024, 16632001f49Smrg 256*1024, 16732001f49Smrg 1024*1024, 16832001f49Smrg 16*1024*1024, 16932001f49Smrg 0 /* end of list */ 17032001f49Smrg}; 17132001f49Smrg 17232001f49Smrgvoid 17332001f49SmrgPerfNextRound(void) 17432001f49Smrg{ 17532001f49Smrg} 17632001f49Smrg 17732001f49Smrg/** Called from test harness/main */ 17832001f49Smrgvoid 17932001f49SmrgPerfDraw(void) 18032001f49Smrg{ 18132001f49Smrg double rate, mbPerSec; 18232001f49Smrg int i, sz; 18332001f49Smrg 18432001f49Smrg /* Load VBOData buffer with duplicated Vertex0. 18532001f49Smrg */ 18632001f49Smrg VBOData = calloc(DATA_SIZE, 1); 18732001f49Smrg 18832001f49Smrg for (i = 0; i < DATA_SIZE / sizeof(Vertex0); i++) { 18932001f49Smrg memcpy(VBOData + i * sizeof(Vertex0), 19032001f49Smrg Vertex0, 19132001f49Smrg sizeof(Vertex0)); 19232001f49Smrg } 19332001f49Smrg 19432001f49Smrg /* glBufferDataARB() 19532001f49Smrg */ 19632001f49Smrg for (sz = 0; Sizes[sz]; sz++) { 19732001f49Smrg SubSize = VBOSize = Sizes[sz]; 19832001f49Smrg rate = PerfMeasureRate(UploadVBO); 19932001f49Smrg mbPerSec = rate * VBOSize / (1024.0 * 1024.0); 20032001f49Smrg perf_printf(" glBufferDataARB(size = %d): %.1f MB/sec\n", 20132001f49Smrg VBOSize, mbPerSec); 20232001f49Smrg } 20332001f49Smrg 20432001f49Smrg /* glBufferSubDataARB() 20532001f49Smrg */ 20632001f49Smrg for (sz = 0; Sizes[sz]; sz++) { 20732001f49Smrg SubSize = VBOSize = Sizes[sz]; 20832001f49Smrg rate = PerfMeasureRate(UploadSubVBO); 20932001f49Smrg mbPerSec = rate * VBOSize / (1024.0 * 1024.0); 21032001f49Smrg perf_printf(" glBufferSubDataARB(size = %d): %.1f MB/sec\n", 21132001f49Smrg VBOSize, mbPerSec); 21232001f49Smrg } 21332001f49Smrg 21432001f49Smrg /* Batch upload 21532001f49Smrg */ 21632001f49Smrg VBOSize = 1024 * 1024; 21732001f49Smrg glBufferDataARB(GL_ARRAY_BUFFER, VBOSize, VBOData, GL_STREAM_DRAW_ARB); 21832001f49Smrg 21932001f49Smrg for (sz = 0; Sizes[sz] < VBOSize; sz++) { 22032001f49Smrg SubSize = Sizes[sz]; 22132001f49Smrg rate = PerfMeasureRate(UploadSubVBO); 22232001f49Smrg mbPerSec = rate * SubSize / (1024.0 * 1024.0); 22332001f49Smrg perf_printf(" glBufferSubDataARB(size = %d, VBOSize = %d): %.1f MB/sec\n", 22432001f49Smrg SubSize, VBOSize, mbPerSec); 22532001f49Smrg } 22632001f49Smrg 22732001f49Smrg for (sz = 0; Sizes[sz] < VBOSize; sz++) { 22832001f49Smrg SubSize = Sizes[sz]; 22932001f49Smrg rate = PerfMeasureRate(BatchUploadSubVBO); 23032001f49Smrg mbPerSec = rate * SubSize / (1024.0 * 1024.0); 23132001f49Smrg perf_printf(" glBufferSubDataARB(size = %d, VBOSize = %d), batched: %.1f MB/sec\n", 23232001f49Smrg SubSize, VBOSize, mbPerSec); 23332001f49Smrg } 23432001f49Smrg 23532001f49Smrg /* Create/Draw/Destroy 23632001f49Smrg */ 23732001f49Smrg for (sz = 0; Sizes[sz]; sz++) { 23832001f49Smrg SubSize = VBOSize = Sizes[sz]; 23932001f49Smrg rate = PerfMeasureRate(CreateDrawDestroyVBO); 24032001f49Smrg mbPerSec = rate * VBOSize / (1024.0 * 1024.0); 24132001f49Smrg perf_printf(" VBO Create/Draw/Destroy(size = %d): %.1f MB/sec, %.1f draws/sec\n", 24232001f49Smrg VBOSize, mbPerSec, rate); 24332001f49Smrg } 24432001f49Smrg 24532001f49Smrg exit(0); 24632001f49Smrg} 247