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