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 glTex[Sub]Image2D() and glGetTexImage() rate 24 * 25 * Brian Paul 26 * 16 Sep 2009 27 */ 28 29#include "glmain.h" 30#include "common.h" 31 32 33int WinWidth = 100, WinHeight = 100; 34 35static GLuint VBO; 36static GLuint TexObj = 0; 37static GLubyte *TexImage = NULL; 38static GLsizei TexSize; 39static GLenum TexIntFormat, TexSrcFormat, TexSrcType; 40 41static const GLboolean DrawPoint = GL_TRUE; 42static const GLboolean TexSubImage4 = GL_FALSE; 43 44enum { 45 MODE_CREATE_TEXIMAGE, 46 MODE_TEXIMAGE, 47 MODE_TEXSUBIMAGE, 48 MODE_GETTEXIMAGE, 49 MODE_COUNT 50}; 51 52static const char *mode_name[MODE_COUNT] = 53{ 54 "Create_TexImage", 55 "TexImage", 56 "TexSubImage", 57 "GetTexImage" 58}; 59 60 61 62struct vertex 63{ 64 GLfloat x, y, s, t; 65}; 66 67static const struct vertex vertices[1] = { 68 { 0.0, 0.0, 0.5, 0.5 }, 69}; 70 71#define VOFFSET(F) ((void *) offsetof(struct vertex, F)) 72 73 74/** Called from test harness/main */ 75void 76PerfInit(void) 77{ 78 /* setup VBO w/ vertex data */ 79 glGenBuffersARB(1, &VBO); 80 glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO); 81 glBufferDataARB(GL_ARRAY_BUFFER_ARB, 82 sizeof(vertices), vertices, GL_STATIC_DRAW_ARB); 83 glVertexPointer(2, GL_FLOAT, sizeof(struct vertex), VOFFSET(x)); 84 glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), VOFFSET(s)); 85 glEnableClientState(GL_VERTEX_ARRAY); 86 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 87 88 /* texture */ 89 glGenTextures(1, &TexObj); 90 glBindTexture(GL_TEXTURE_2D, TexObj); 91 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 92 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 93 glEnable(GL_TEXTURE_2D); 94} 95 96 97 98 99static void 100CreateUploadTexImage2D(unsigned count) 101{ 102 unsigned i; 103 for (i = 0; i < count; i++) { 104 if (TexObj) 105 glDeleteTextures(1, &TexObj); 106 107 glGenTextures(1, &TexObj); 108 glBindTexture(GL_TEXTURE_2D, TexObj); 109 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 111 112 glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, 113 TexSize, TexSize, 0, 114 TexSrcFormat, TexSrcType, TexImage); 115 116 if (DrawPoint) 117 glDrawArrays(GL_POINTS, 0, 1); 118 } 119 glFinish(); 120} 121 122 123static void 124UploadTexImage2D(unsigned count) 125{ 126 unsigned i; 127 for (i = 0; i < count; i++) { 128 /* XXX is this equivalent to a glTexSubImage call since we're 129 * always specifying the same image size? That case isn't optimized 130 * in Mesa but may be optimized in other drivers. Note sure how 131 * much difference that might make. 132 */ 133 glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, 134 TexSize, TexSize, 0, 135 TexSrcFormat, TexSrcType, TexImage); 136 if (DrawPoint) 137 glDrawArrays(GL_POINTS, 0, 1); 138 } 139 glFinish(); 140} 141 142 143static void 144UploadTexSubImage2D(unsigned count) 145{ 146 unsigned i; 147 for (i = 0; i < count; i++) { 148 if (TexSubImage4) { 149 GLsizei halfSize = (TexSize == 1) ? 1 : TexSize / 2; 150 GLsizei halfPos = TexSize - halfSize; 151 /* do glTexSubImage2D in four pieces */ 152 /* lower-left */ 153 glPixelStorei(GL_UNPACK_ROW_LENGTH, TexSize); 154 glTexSubImage2D(GL_TEXTURE_2D, 0, 155 0, 0, halfSize, halfSize, 156 TexSrcFormat, TexSrcType, TexImage); 157 /* lower-right */ 158 glPixelStorei(GL_UNPACK_SKIP_PIXELS, halfPos); 159 glTexSubImage2D(GL_TEXTURE_2D, 0, 160 halfPos, 0, halfSize, halfSize, 161 TexSrcFormat, TexSrcType, TexImage); 162 /* upper-left */ 163 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 164 glPixelStorei(GL_UNPACK_SKIP_ROWS, halfPos); 165 glTexSubImage2D(GL_TEXTURE_2D, 0, 166 0, halfPos, halfSize, halfSize, 167 TexSrcFormat, TexSrcType, TexImage); 168 /* upper-right */ 169 glPixelStorei(GL_UNPACK_SKIP_PIXELS, halfPos); 170 glPixelStorei(GL_UNPACK_SKIP_ROWS, halfPos); 171 glTexSubImage2D(GL_TEXTURE_2D, 0, 172 halfPos, halfPos, halfSize, halfSize, 173 TexSrcFormat, TexSrcType, TexImage); 174 /* reset the unpacking state */ 175 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 176 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 177 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 178 } 179 else { 180 /* replace whole texture image at once */ 181 glTexSubImage2D(GL_TEXTURE_2D, 0, 182 0, 0, TexSize, TexSize, 183 TexSrcFormat, TexSrcType, TexImage); 184 } 185 if (DrawPoint) 186 glDrawArrays(GL_POINTS, 0, 1); 187 } 188 glFinish(); 189} 190 191 192static void 193GetTexImage2D(unsigned count) 194{ 195 unsigned i; 196 GLubyte *buf = (GLubyte *) malloc(TexSize * TexSize * 4); 197 for (i = 0; i < count; i++) { 198 glGetTexImage(GL_TEXTURE_2D, 0, 199 TexSrcFormat, TexSrcType, buf); 200 } 201 glFinish(); 202 free(buf); 203} 204 205 206/* XXX any other formats to measure? */ 207static const struct { 208 GLenum format, type; 209 GLenum internal_format; 210 const char *name; 211 GLuint texel_size; 212 GLboolean full_test; 213} SrcFormats[] = { 214 { GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, "RGBA/ubyte", 4, GL_TRUE }, 215 { GL_RGB, GL_UNSIGNED_BYTE, GL_RGB, "RGB/ubyte", 3, GL_FALSE }, 216 { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB, "RGB/565", 2, GL_FALSE }, 217 { GL_BGRA, GL_UNSIGNED_BYTE, GL_RGBA, "BGRA/ubyte", 4, GL_FALSE }, 218 { GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE, "L/ubyte", 1, GL_FALSE }, 219 { 0, 0, 0, NULL, 0, 0 } 220}; 221 222 223/** Called from test harness/main */ 224void 225PerfNextRound(void) 226{ 227} 228 229 230/** Called from test harness/main */ 231void 232PerfDraw(void) 233{ 234 GLint maxSize; 235 double rate; 236 GLint fmt, mode; 237 238 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); 239 240 /* loop over source data formats */ 241 for (fmt = 0; SrcFormats[fmt].format; fmt++) { 242 TexIntFormat = SrcFormats[fmt].internal_format; 243 TexSrcFormat = SrcFormats[fmt].format; 244 TexSrcType = SrcFormats[fmt].type; 245 246 /* loop over glTexImage, glTexSubImage */ 247 for (mode = 0; mode < MODE_COUNT; mode++) { 248 GLuint minsz, maxsz; 249 250 if (SrcFormats[fmt].full_test) { 251 minsz = 16; 252 maxsz = 4096; 253 } 254 else { 255 minsz = maxsz = 256; 256 if (mode == MODE_CREATE_TEXIMAGE) 257 continue; 258 } 259 260 /* loop over a defined range of texture sizes, test only the 261 * ones which are legal for this driver. 262 */ 263 for (TexSize = minsz; TexSize <= maxsz; TexSize *= 4) { 264 double mbPerSec; 265 266 if (TexSize <= maxSize) { 267 GLint bytesPerImage; 268 269 bytesPerImage = TexSize * TexSize * SrcFormats[fmt].texel_size; 270 TexImage = malloc(bytesPerImage); 271 272 switch (mode) { 273 case MODE_TEXIMAGE: 274 rate = PerfMeasureRate(UploadTexImage2D); 275 break; 276 277 case MODE_CREATE_TEXIMAGE: 278 rate = PerfMeasureRate(CreateUploadTexImage2D); 279 break; 280 281 case MODE_TEXSUBIMAGE: 282 /* create initial, empty texture */ 283 glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, 284 TexSize, TexSize, 0, 285 TexSrcFormat, TexSrcType, NULL); 286 rate = PerfMeasureRate(UploadTexSubImage2D); 287 break; 288 289 case MODE_GETTEXIMAGE: 290 glTexImage2D(GL_TEXTURE_2D, 0, TexIntFormat, 291 TexSize, TexSize, 0, 292 TexSrcFormat, TexSrcType, TexImage); 293 rate = PerfMeasureRate(GetTexImage2D); 294 break; 295 296 default: 297 exit(1); 298 } 299 300 mbPerSec = rate * bytesPerImage / (1024.0 * 1024.0); 301 free(TexImage); 302 303 304 { 305 unsigned err; 306 err = glGetError(); 307 if (err) { 308 perf_printf("non-zero glGetError() %d\n", err); 309 exit(1); 310 } 311 } 312 313 } 314 else { 315 rate = 0; 316 mbPerSec = 0; 317 } 318 319 perf_printf(" %s(%s %d x %d): " 320 "%.1f images/sec, %.1f MB/sec\n", 321 mode_name[mode], 322 SrcFormats[fmt].name, TexSize, TexSize, rate, mbPerSec); 323 } 324 325 if (SrcFormats[fmt].full_test) 326 perf_printf("\n"); 327 } 328 } 329 330 exit(0); 331} 332