Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

texdown.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. * Copyright (C) 1999 Brian Paul 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. * BRIAN PAUL 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. * texdown
  23. *
  24. * Measure texture download speed.
  25. * Use keyboard to change texture size, format, datatype, scale/bias,
  26. * subimageload, etc.
  27. *
  28. * Brian Paul 28 January 2000
  29. */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <math.h>
  33. #include <GL/glut.h>
  34. static GLsizei MaxSize = 2048;
  35. static GLsizei TexWidth = 1024, TexHeight = 1024, TexBorder = 0;
  36. static GLboolean ScaleAndBias = GL_FALSE;
  37. static GLboolean SubImage = GL_FALSE;
  38. static GLdouble DownloadRate = 0.0; /* texels/sec */
  39. static GLuint Mode = 0;
  40. /* Try and avoid L2 cache effects by cycling through a small number of
  41. * textures.
  42. *
  43. * At the initial size of 1024x1024x4 == 4mbyte, say 8 textures will
  44. * keep us out of most caches at 32mb total.
  45. *
  46. * This turns into a fairly interesting question of what exactly you
  47. * expect to be in cache in normal usage, and what you think should be
  48. * outside. There's no rules for this, no reason to favour one usage
  49. * over another except what the application you care about happens to
  50. * resemble most closely.
  51. *
  52. * - Should the client texture image be in L2 cache? Has it just been
  53. * generated or read from disk?
  54. * - Does the application really use >1 texture, or is it constantly
  55. * updating one image in-place?
  56. *
  57. * Different answers will favour different texture upload mechanisms.
  58. * To upload an image that is purely outside of cache, a DMA-based
  59. * upload will probably win, whereas for small, in-cache textures,
  60. * copying looks good.
  61. */
  62. #define NR_TEXOBJ 4
  63. static GLuint TexObj[NR_TEXOBJ];
  64. struct FormatRec {
  65. GLenum Format;
  66. GLenum Type;
  67. GLenum IntFormat;
  68. GLint TexelSize;
  69. };
  70. static const struct FormatRec FormatTable[] = {
  71. /* Format Type IntFormat TexelSize */
  72. { GL_BGRA, GL_UNSIGNED_BYTE, GL_RGBA, 4 },
  73. { GL_RGB, GL_UNSIGNED_BYTE, GL_RGB, 3 },
  74. { GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, 4 },
  75. { GL_RGBA, GL_UNSIGNED_BYTE, GL_RGB, 4 },
  76. { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB, 2 },
  77. { GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE, 1 },
  78. { GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE_ALPHA, 2 },
  79. { GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA, 1 },
  80. };
  81. static GLint Format;
  82. #define NUM_FORMATS (sizeof(FormatTable)/sizeof(FormatTable[0]))
  83. static int
  84. BytesPerTexel(GLint format)
  85. {
  86. return FormatTable[format].TexelSize;
  87. }
  88. static const char *
  89. FormatStr(GLenum format)
  90. {
  91. switch (format) {
  92. case GL_RGB:
  93. return "GL_RGB";
  94. case GL_RGBA:
  95. return "GL_RGBA";
  96. case GL_BGRA:
  97. return "GL_BGRA";
  98. case GL_LUMINANCE:
  99. return "GL_LUMINANCE";
  100. case GL_LUMINANCE_ALPHA:
  101. return "GL_LUMINANCE_ALPHA";
  102. case GL_ALPHA:
  103. return "GL_ALPHA";
  104. default:
  105. return "";
  106. }
  107. }
  108. static const char *
  109. TypeStr(GLenum type)
  110. {
  111. switch (type) {
  112. case GL_UNSIGNED_BYTE:
  113. return "GL_UNSIGNED_BYTE";
  114. case GL_UNSIGNED_SHORT:
  115. return "GL_UNSIGNED_SHORT";
  116. case GL_UNSIGNED_SHORT_5_6_5:
  117. return "GL_UNSIGNED_SHORT_5_6_5";
  118. case GL_UNSIGNED_SHORT_5_6_5_REV:
  119. return "GL_UNSIGNED_SHORT_5_6_5_REV";
  120. default:
  121. return "";
  122. }
  123. }
  124. /* On x86, there is a performance cliff for memcpy to texture memory
  125. * for sources below 64 byte alignment. We do our best with this in
  126. * the driver, but it is better if the images are correctly aligned to
  127. * start with:
  128. */
  129. #define ALIGN (1<<12)
  130. static unsigned long align(unsigned long value, unsigned long a)
  131. {
  132. return (value + a - 1) & ~(a-1);
  133. }
  134. static int MIN2(int a, int b)
  135. {
  136. return a < b ? a : b;
  137. }
  138. static void
  139. MeasureDownloadRate(void)
  140. {
  141. const int w = TexWidth + 2 * TexBorder;
  142. const int h = TexHeight + 2 * TexBorder;
  143. const int image_bytes = align(w * h * BytesPerTexel(Format), ALIGN);
  144. const int bytes = image_bytes * NR_TEXOBJ;
  145. GLubyte *orig_texImage, *orig_getImage;
  146. GLubyte *texImage, *getImage;
  147. GLdouble t0, t1, time;
  148. int count;
  149. int i;
  150. int offset = 0;
  151. GLdouble total = 0; /* ints will tend to overflow */
  152. printf("allocating %d bytes for %d %dx%d images\n",
  153. bytes, NR_TEXOBJ, w, h);
  154. orig_texImage = (GLubyte *) malloc(bytes + ALIGN);
  155. orig_getImage = (GLubyte *) malloc(image_bytes + ALIGN);
  156. if (!orig_texImage || !orig_getImage) {
  157. DownloadRate = 0.0;
  158. return;
  159. }
  160. printf("alloc %p %p\n", orig_texImage, orig_getImage);
  161. texImage = (GLubyte *)align((unsigned long)orig_texImage, ALIGN);
  162. getImage = (GLubyte *)align((unsigned long)orig_getImage, ALIGN);
  163. for (i = 1; !(((unsigned long)texImage) & i); i<<=1)
  164. ;
  165. printf("texture image alignment: %d bytes (%p)\n", i, texImage);
  166. for (i = 0; i < bytes; i++) {
  167. texImage[i] = i & 0xff;
  168. }
  169. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  170. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  171. if (ScaleAndBias) {
  172. glPixelTransferf(GL_RED_SCALE, 0.5);
  173. glPixelTransferf(GL_GREEN_SCALE, 0.5);
  174. glPixelTransferf(GL_BLUE_SCALE, 0.5);
  175. glPixelTransferf(GL_RED_BIAS, 0.5);
  176. glPixelTransferf(GL_GREEN_BIAS, 0.5);
  177. glPixelTransferf(GL_BLUE_BIAS, 0.5);
  178. }
  179. else {
  180. glPixelTransferf(GL_RED_SCALE, 1.0);
  181. glPixelTransferf(GL_GREEN_SCALE, 1.0);
  182. glPixelTransferf(GL_BLUE_SCALE, 1.0);
  183. glPixelTransferf(GL_RED_BIAS, 0.0);
  184. glPixelTransferf(GL_GREEN_BIAS, 0.0);
  185. glPixelTransferf(GL_BLUE_BIAS, 0.0);
  186. }
  187. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  188. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  189. glEnable(GL_TEXTURE_2D);
  190. count = 0;
  191. t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
  192. do {
  193. int img = count%NR_TEXOBJ;
  194. GLubyte *img_ptr = texImage + img * image_bytes;
  195. glBindTexture(GL_TEXTURE_2D, TexObj[img]);
  196. if (SubImage && count > 0) {
  197. /* Only update a portion of the image each iteration. This
  198. * is presumably why you'd want to use texsubimage, otherwise
  199. * you may as well just call teximage again.
  200. *
  201. * A bigger question is whether to use a pointer that moves
  202. * with each call, ie does the incoming data come from L2
  203. * cache under normal circumstances, or is it pulled from
  204. * uncached memory?
  205. *
  206. * There's a good argument to say L2 cache, ie you'd expect
  207. * the data to have been recently generated. It's possible
  208. * that it could have come from a file read, which may or may
  209. * not have gone through the cpu.
  210. */
  211. glTexSubImage2D(GL_TEXTURE_2D, 0,
  212. -TexBorder,
  213. -TexBorder + offset * h/8,
  214. w,
  215. h/8,
  216. FormatTable[Format].Format,
  217. FormatTable[Format].Type,
  218. #if 1
  219. texImage /* likely in L2$ */
  220. #else
  221. img_ptr + offset * bytes/8 /* unlikely in L2$ */
  222. #endif
  223. );
  224. offset += 1;
  225. offset %= 8;
  226. total += w * h / 8;
  227. }
  228. else {
  229. glTexImage2D(GL_TEXTURE_2D, 0,
  230. FormatTable[Format].IntFormat, w, h, TexBorder,
  231. FormatTable[Format].Format,
  232. FormatTable[Format].Type,
  233. img_ptr);
  234. total += w*h;
  235. }
  236. /* draw a tiny polygon to force texture into texram */
  237. glBegin(GL_TRIANGLES);
  238. glTexCoord2f(0, 0); glVertex2f(1, 1);
  239. glTexCoord2f(1, 0); glVertex2f(3, 1);
  240. glTexCoord2f(0.5, 1); glVertex2f(2, 3);
  241. glEnd();
  242. t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
  243. time = t1 - t0;
  244. count++;
  245. } while (time < 3.0);
  246. glDisable(GL_TEXTURE_2D);
  247. printf("total texels=%f time=%f\n", total, time);
  248. DownloadRate = total / time;
  249. free(orig_texImage);
  250. free(orig_getImage);
  251. {
  252. GLint err = glGetError();
  253. if (err)
  254. printf("GL error %d\n", err);
  255. }
  256. }
  257. static void
  258. PrintString(const char *s)
  259. {
  260. while (*s) {
  261. glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
  262. s++;
  263. }
  264. }
  265. static void
  266. Display(void)
  267. {
  268. const int w = TexWidth + 2 * TexBorder;
  269. const int h = TexHeight + 2 * TexBorder;
  270. char s[1000];
  271. glClear(GL_COLOR_BUFFER_BIT);
  272. glRasterPos2i(10, 80);
  273. sprintf(s, "Texture size[cursor]: %d x %d Border[b]: %d", w, h, TexBorder);
  274. PrintString(s);
  275. glRasterPos2i(10, 65);
  276. sprintf(s, "Format[f]: %s Type: %s IntFormat: %s",
  277. FormatStr(FormatTable[Format].Format),
  278. TypeStr( FormatTable[Format].Type),
  279. FormatStr(FormatTable[Format].IntFormat));
  280. PrintString(s);
  281. glRasterPos2i(10, 50);
  282. sprintf(s, "Pixel Scale&Bias[p]: %s TexSubImage[s]: %s",
  283. ScaleAndBias ? "Yes" : "No",
  284. SubImage ? "Yes" : "No");
  285. PrintString(s);
  286. if (Mode == 0) {
  287. glRasterPos2i(200, 10);
  288. sprintf(s, "...Measuring...");
  289. PrintString(s);
  290. glutSwapBuffers();
  291. glutPostRedisplay();
  292. Mode++;
  293. }
  294. else if (Mode == 1) {
  295. MeasureDownloadRate();
  296. glutPostRedisplay();
  297. Mode++;
  298. }
  299. else {
  300. /* show results */
  301. glRasterPos2i(10, 10);
  302. sprintf(s, "Download rate: %g Mtexels/second %g MB/second",
  303. DownloadRate / 1000000.0,
  304. DownloadRate * BytesPerTexel(Format) / 1000000.0);
  305. PrintString(s);
  306. {
  307. GLint r, g, b, a, l, i;
  308. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, &r);
  309. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_SIZE, &g);
  310. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_SIZE, &b);
  311. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &a);
  312. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_LUMINANCE_SIZE, &l);
  313. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTENSITY_SIZE, &i);
  314. sprintf(s, "TexelBits: R=%d G=%d B=%d A=%d L=%d I=%d", r, g, b, a, l, i);
  315. glRasterPos2i(10, 25);
  316. PrintString(s);
  317. }
  318. glutSwapBuffers();
  319. }
  320. }
  321. static void
  322. Reshape(int width, int height)
  323. {
  324. glViewport( 0, 0, width, height );
  325. glMatrixMode( GL_PROJECTION );
  326. glLoadIdentity();
  327. glOrtho(0, width, 0, height, -1, 1);
  328. glMatrixMode( GL_MODELVIEW );
  329. glLoadIdentity();
  330. }
  331. static void
  332. Key(unsigned char key, int x, int y)
  333. {
  334. (void) x;
  335. (void) y;
  336. switch (key) {
  337. case ' ':
  338. Mode = 0;
  339. break;
  340. case 'b':
  341. /* toggle border */
  342. TexBorder = 1 - TexBorder;
  343. Mode = 0;
  344. break;
  345. case 'f':
  346. /* change format */
  347. Format = (Format + 1) % NUM_FORMATS;
  348. Mode = 0;
  349. break;
  350. case 'F':
  351. /* change format */
  352. Format = (Format - 1) % NUM_FORMATS;
  353. Mode = 0;
  354. break;
  355. case 'p':
  356. /* toggle border */
  357. ScaleAndBias = !ScaleAndBias;
  358. Mode = 0;
  359. break;
  360. case 's':
  361. SubImage = !SubImage;
  362. Mode = 0;
  363. break;
  364. case 27:
  365. exit(0);
  366. break;
  367. }
  368. glutPostRedisplay();
  369. }
  370. static void
  371. SpecialKey(int key, int x, int y)
  372. {
  373. (void) x;
  374. (void) y;
  375. switch (key) {
  376. case GLUT_KEY_UP:
  377. if (TexHeight < MaxSize)
  378. TexHeight *= 2;
  379. break;
  380. case GLUT_KEY_DOWN:
  381. if (TexHeight > 1)
  382. TexHeight /= 2;
  383. break;
  384. case GLUT_KEY_LEFT:
  385. if (TexWidth > 1)
  386. TexWidth /= 2;
  387. break;
  388. case GLUT_KEY_RIGHT:
  389. if (TexWidth < MaxSize)
  390. TexWidth *= 2;
  391. break;
  392. }
  393. Mode = 0;
  394. glutPostRedisplay();
  395. }
  396. static void
  397. Init(void)
  398. {
  399. printf("GL_VENDOR = %s\n", (const char *) glGetString(GL_VENDOR));
  400. printf("GL_VERSION = %s\n", (const char *) glGetString(GL_VERSION));
  401. printf("GL_RENDERER = %s\n", (const char *) glGetString(GL_RENDERER));
  402. }
  403. int
  404. main(int argc, char *argv[])
  405. {
  406. glutInit( &argc, argv );
  407. glutInitWindowPosition( 0, 0 );
  408. glutInitWindowSize( 600, 100 );
  409. glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
  410. glutCreateWindow(argv[0]);
  411. glutReshapeFunc( Reshape );
  412. glutKeyboardFunc( Key );
  413. glutSpecialFunc( SpecialKey );
  414. glutDisplayFunc( Display );
  415. Init();
  416. glutMainLoop();
  417. return 0;
  418. }