Optimizing OpenGL (SwapBuffer being slow)

Reply

Join Date: May 2008
Posts: 371
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Optimizing OpenGL (SwapBuffer being slow)

 
0
  #1
Jul 20th, 2008
EDIT for moderators:
Yes that "one might think that swapbuffer is slow" was me. Heh. Could someone change the topicname to "Optimizing OpenGL"? Thanks.

Hey guys,

I'm trying to optimize this OpenGL program, so the problem isn't C, but the program is.

The program loads a vanilla WaveFront .obj file, stores all it's data in an array, creates a display list, uses glDrawElements to put it in the display list and then calls the display list as often as it can. For my test file, this "how often as it can" gives an FPS of about 37. While this is acceptable, another program that does the same manages to do it at 60 FPS.

How do I achieve that performance in this program? The bottleneck appears to be the RenderScene function. It only shows when using glFinish(), else one might think SwapBuffer() takes that amount of time (SwapBuffer waits, of course, for the videocard to finish its rendering). Anyway, from beginning RenderScene to the return of SwapBuffer takes too much time. Too much CPU time that is! My Intel blah blah dual core has once core fully eaten up by this code, and I have no clue why.

Here is the output from the sourcecode below:
  1. WM_TIMER took: Time elapsed: 31
  2. WM_TIMER took: Time elapsed: 16
  3. WM_TIMER took: Time elapsed: 31
  4. WM_TIMER took: Time elapsed: 31
  5. WM_TIMER took: Time elapsed: 31
  6. WM_TIMER took: Time elapsed: 16
  7. WM_TIMER took: Time elapsed: 31
  8. WM_TIMER took: Time elapsed: 32
  9. WM_TIMER took: Time elapsed: 31
  10. WM_TIMER took: Time elapsed: 31
  11. WM_TIMER took: Time elapsed: 16
  12. WM_TIMER took: Time elapsed: 31
  13. WM_TIMER took: Time elapsed: 31
  14. WM_TIMER took: Time elapsed: 31
  15. WM_TIMER took: Time elapsed: 16
  16. WM_TIMER took: Time elapsed: 31
  17. WM_TIMER took: Time elapsed: 32
  18. WM_TIMER took: Time elapsed: 31
  19. WM_TIMER took: Time elapsed: 15
  20. WM_TIMER took: Time elapsed: 32
  21. WM_TIMER took: Time elapsed: 31
  22. WM_TIMER took: Time elapsed: 31
  23. WM_TIMER took: Time elapsed: 0
  24. WM_TIMER took: Time elapsed: 16
  25. WM_TIMER took: Time elapsed: 31
  26. WM_TIMER took: Time elapsed: 16
  27. WM_TIMER took: Time elapsed: 31
  28. WM_TIMER took: Time elapsed: 31
  29. WM_TIMER took: Time elapsed: 31
  30. WM_TIMER took: Time elapsed: 16
  31. WM_TIMER took: Time elapsed: 31
  32. WM_TIMER took: Time elapsed: 31
  33. WM_TIMER took: Time elapsed: 32
  34. WM_TIMER took: Time elapsed: 15
  35. WM_TIMER took: Time elapsed: 32
  36. WM_TIMER took: Time elapsed: 31
  37. FPS: 36

How can I speed this up?
Thanks in Advance,
Nick

Code:
BowViceJet.c
  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <gl/gl.h>
  4. #include <gl/glu.h>
  5. #include <gl/glext.h>
  6. #include <time.h>
  7. #include "loadObj.h"
  8.  
  9. #define TIMEELAPSED {printf("\tTime elapsed: %lu\n", clock() - startTime);}
  10.  
  11. int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow);
  12. LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
  13.  
  14. void dbgError(char *msg);
  15. void MySetPixelFormat(HDC hDC);
  16.  
  17. void RenderScene();
  18. void ChangeSize(int width, int height);
  19. int initGL();
  20. void pressKey(WPARAM key);
  21.  
  22. const static char className[] = "OpenGLClass";
  23. const static char appName[] = "OpenGL Window";
  24.  
  25. GLfloat xRot, yRot, zRot;
  26. GLfloat xDis, yDis, zDis;
  27.  
  28. float *vertices, *normals;
  29. int *triangleindex, *quadindex;
  30. unsigned int quadcount, trianglecount;
  31.  
  32. int err;
  33. char *globcmdLine;
  34.  
  35. unsigned int globDisplayLists = 0;
  36.  
  37. char optFrontFace = 0; //CCW default
  38.  
  39. void dbgError(char *msg){
  40. fprintf(stderr, "Error @ %s. GetLastError(): %lu", msg, GetLastError());
  41. return;
  42. }
  43.  
  44. int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow){
  45. globcmdLine = cmdLine;
  46. MSG msg;
  47. WNDCLASS wc;
  48. HWND hWnd;
  49.  
  50. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  51. wc.lpfnWndProc = (WNDPROC) WndProc;
  52. wc.cbClsExtra = 0;
  53. wc.cbWndExtra = 0;
  54. wc.hInstance = instance;
  55. wc.hIcon = NULL;
  56. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  57. wc.hbrBackground = NULL;
  58. wc.lpszMenuName = NULL;
  59. wc.lpszClassName = className;
  60.  
  61. if(RegisterClass(&wc) == 0){
  62. dbgError("RegisterClass()");
  63. return -1;
  64. }
  65.  
  66. const DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  67. const int xPos = 0;
  68. const int yPos = 0;
  69. const int width = 640;
  70. const int height = 480;
  71.  
  72. hWnd = CreateWindow(className, appName, style, xPos, yPos, width, height, NULL, NULL, instance, NULL);
  73.  
  74. if(hWnd == NULL){
  75. dbgError("CreateWindow()");
  76. return -1;
  77. }
  78.  
  79. ShowWindow(hWnd, SW_SHOW);
  80. UpdateWindow(hWnd);
  81.  
  82. int ret;
  83.  
  84. while((ret = GetMessage(&msg, NULL, 0, 0)) > 0){
  85. TranslateMessage(&msg);
  86. DispatchMessage(&msg);
  87. }
  88.  
  89. if(ret == -1){
  90. dbgError("GetMessage()");
  91. return -1;
  92. }
  93. printf("Exiting from WinMain! G'bye.\n");
  94. return msg.wParam;
  95. }
  96.  
  97. LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
  98. static HGLRC hRC = NULL;
  99. static HDC hDC = NULL;
  100. clock_t startTime;
  101.  
  102. switch(msg){
  103. case WM_TIMER:
  104. startTime = clock();
  105. RenderScene();
  106. xRot += 0.5;
  107. yRot += 0.5;
  108. zRot += 0.5;
  109. SwapBuffers(hDC);
  110. printf("WM_TIMER took: "); TIMEELAPSED
  111. break;
  112.  
  113. case WM_CREATE:
  114. hDC = GetDC(hWnd);
  115. MySetPixelFormat(hDC);
  116. hRC = wglCreateContext(hDC);
  117. if (hRC == NULL){
  118. unsigned long err = GetLastError();
  119. char *msg = calloc(sizeof(char), 512);
  120. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, 512, 0);
  121. printf("wglCreateContext() failed: error nr. %lu:\n\t%s\n", err, msg);
  122. }
  123. if (wglMakeCurrent(hDC, hRC) == FALSE){
  124. unsigned long err = GetLastError();
  125. char *msg = calloc(sizeof(char), 512);
  126. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, 512, 0);
  127. printf("wglMakeCurrent() failed: error nr. %lu:\n\t%s\n", err, msg);
  128. }
  129.  
  130. if(initGL() < 0){
  131. printf("Error loading in model. Exiting");
  132. exit(1);
  133. }
  134. else{
  135. printf("Model loaded and ready to go!\n");
  136. }
  137. //fire as often as it can
  138. SetTimer(hWnd, 0, 1, NULL);
  139. printf("Running with GL_VENDOR: %s\n", glGetString(GL_VENDOR));
  140. break;
  141.  
  142. case WM_DESTROY:
  143. wglMakeCurrent(hDC, NULL);
  144. wglDeleteContext(hRC);
  145. PostQuitMessage(0);
  146. break;
  147.  
  148. case WM_PAINT:
  149. //printf("WM_PAINTING. ;-)\n");
  150. RenderScene();
  151. SwapBuffers(hDC);
  152. ValidateRect(hWnd, NULL);
  153. break;
  154.  
  155. case WM_SIZE:
  156. ChangeSize(LOWORD(lParam), HIWORD(lParam));
  157. break;
  158.  
  159. case WM_KEYDOWN:
  160. pressKey(wParam);
  161. break;
  162.  
  163. default:
  164. return (DefWindowProc(hWnd, msg, wParam, lParam));
  165. break;
  166. }
  167.  
  168. return 0;
  169. }
  170.  
  171. void MySetPixelFormat(HDC hDC){
  172. int pixelFormat;
  173.  
  174. static PIXELFORMATDESCRIPTOR pfd = {
  175. sizeof(PIXELFORMATDESCRIPTOR),
  176. 1,
  177. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA,
  178. 32, //depth of color
  179. 0,0,0,0,0,0,0,0,0,0,0,0,0,
  180. 16 , //depth of depthbuffer
  181. 0,0,0,0,0,0,0};
  182.  
  183. pixelFormat = ChoosePixelFormat(hDC, &pfd);
  184. if (SetPixelFormat(hDC, pixelFormat, &pfd) == FALSE){
  185. unsigned long err = GetLastError();
  186. char *msg = calloc(sizeof(char), 512);
  187. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, 512, 0);
  188. printf("SetPixelFormat() failed: error nr. %lu:\n\t%s\n", err, msg);
  189. }
  190. return;
  191. }
  192.  
  193. void RenderScene(){
  194. //printf("Rendering scene...\n");
  195. static clock_t nextSecond = 0;
  196. static unsigned int framesPerSecond = 0;
  197. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  198. clock_t startTime = clock();
  199.  
  200. //glMatrixMode(GL_MODELVIEW);
  201.  
  202. if(optFrontFace){
  203. glFrontFace(GL_CW);
  204. }
  205. else{
  206. glFrontFace(GL_CCW);
  207. }
  208.  
  209. glPushMatrix();
  210. glTranslatef(xDis, yDis, zDis-20);
  211.  
  212. glRotatef(xRot, 1, 0, 0);
  213. glRotatef(yRot, 0, 1, 0);
  214. glRotatef(zRot, 0, 0, 1);
  215.  
  216. glColor3f(.5, .6, .6);
  217.  
  218. //printf("Quadindex: %p\tTriangleindex: %p\n", quadindex, triangleindex);
  219. //printf("Quadcount: %u\tTrianglecount: %u\n", quadcount, trianglecount);
  220. glCallList(globDisplayLists);
  221.  
  222. glPopMatrix();
  223.  
  224. //glDisableClientState(GL_VERTEX_ARRAY);
  225. //glDisableClientState(GL_NORMAL_ARRAY);
  226. framesPerSecond++;
  227.  
  228. if(clock() >= nextSecond){
  229. nextSecond = clock() + CLOCKS_PER_SEC;
  230. printf("FPS: %u\n", framesPerSecond);
  231. framesPerSecond = 0;
  232. }
  233.  
  234. return;
  235. }
  236.  
  237. void ChangeSize(int width, int height){
  238. if (height == 0) height = 1;
  239. GLfloat aspect = (GLfloat)width/(GLfloat)height;
  240.  
  241. glViewport(0, 0, width, height);
  242.  
  243. glMatrixMode(GL_PROJECTION);
  244. glLoadIdentity();
  245.  
  246. gluPerspective(60, aspect, 0.1, 1000);
  247.  
  248. glMatrixMode(GL_MODELVIEW);
  249. glLoadIdentity();
  250. return;
  251. }
  252.  
  253. int initGL(){
  254. xRot = yRot = zRot = 0;
  255. xDis = yDis = zDis = 0;
  256.  
  257. vertices = normals = NULL;
  258. triangleindex = quadindex = NULL;
  259. quadcount = trianglecount = 0;
  260.  
  261.  
  262. glFrontFace(GL_CCW);
  263. glEnable(GL_DEPTH_TEST);
  264. glEnable(GL_CULL_FACE);
  265. glEnable(GL_LIGHTING);
  266.  
  267. //lighting colors
  268. GLfloat ambient[] = {0.35, 0.35, 0.35, 1.0};
  269. GLfloat diffuse[] = {0.5, 0.5, 0.5, 1.0};
  270. //GLfloat specular[] = {1, 1, 1, 1};
  271. GLfloat light0Pos[] = {-60, 10, 10, 1};
  272. GLfloat light1Pos[] = {60, 10, 10, 1};
  273.  
  274. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
  275. glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  276. glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  277. //glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
  278. glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
  279. glEnable(GL_LIGHT0);
  280.  
  281. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
  282. glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
  283. glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
  284. //glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
  285. glLightfv(GL_LIGHT1, GL_POSITION, light1Pos);
  286. glEnable(GL_LIGHT1);
  287.  
  288. glEnable(GL_COLOR_MATERIAL);
  289. glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  290.  
  291. //GLfloat specref[] = {1, 1, 1, 1};
  292. //glMaterialfv(GL_FRONT, GL_SPECULAR, specref);
  293. //glMateriali(GL_FRONT, GL_SHININESS, 120);
  294.  
  295. glClearColor(0.0, 0.0, 0.0, 1.0);
  296. err = loadObj(globcmdLine, &vertices, &normals, &triangleindex, &quadindex, &quadcount, &trianglecount);
  297. if(err < 0){
  298. printf("loadObj failed to load object!");
  299. return -1;
  300. }
  301. if(vertices == NULL || normals == NULL || (triangleindex == NULL && quadindex == NULL)){
  302. printf("Error! One of the essential pointers == NULL!");
  303. return -1;
  304. }
  305.  
  306. //printf("Enabling vertex and normal arrays...");
  307. glEnableClientState(GL_VERTEX_ARRAY);
  308. glEnableClientState(GL_NORMAL_ARRAY);
  309. //printf("Done\n");
  310.  
  311. //printf("Vertices: %p\tNormals: %p\n", vertices, normals);
  312. glVertexPointer(3, GL_FLOAT, 0, vertices);
  313. glNormalPointer(GL_FLOAT, 0, normals);
  314.  
  315. globDisplayLists = glGenLists(1);
  316.  
  317. glNewList(globDisplayLists, GL_COMPILE);
  318. glDrawElements(GL_QUADS, quadcount*4, GL_UNSIGNED_INT, quadindex);
  319. glDrawElements(GL_TRIANGLES, trianglecount*3, GL_UNSIGNED_INT, triangleindex);
  320. glEndList();
  321.  
  322. return 0;
  323. }
  324.  
  325. void pressKey(WPARAM key){
  326.  
  327. #define KEYPRESS(x, a, b, c){\
  328. case x:\
  329. a b c;\
  330. break;\
  331. }
  332.  
  333. #define KEYPAIR(keyone, keytwo, var, val){\
  334. KEYPRESS(keyone, var, +=, val);\
  335. KEYPRESS(keytwo, var, -=, val);\
  336. }
  337.  
  338. #define OPTION(key, optname){\
  339. KEYPRESS(key, optname, ^=, 1);\
  340. }
  341.  
  342. static float STRENGTH = 1;
  343. switch (key){
  344. //rotation
  345. KEYPAIR('Q', 'E', yRot, (STRENGTH*2));
  346. KEYPAIR('A', 'D', xRot, (STRENGTH*2));
  347. KEYPAIR('Z', 'C', zRot, (STRENGTH*2));
  348.  
  349. //displacement
  350. KEYPAIR(VK_RIGHT, VK_LEFT, xDis, STRENGTH);
  351. KEYPAIR(VK_UP, VK_DOWN, yDis, STRENGTH);
  352. KEYPAIR(VK_CONTROL, VK_NUMPAD0, zDis, STRENGTH);
  353.  
  354. //options
  355. OPTION('F', optFrontFace);
  356.  
  357. //STRENGTH adjustment :D
  358. KEYPAIR('O', 'P', STRENGTH, 0.01);
  359. }
  360. printf("Strength: %f\n", STRENGTH);
  361.  
  362. #define ROUNDTHREESIXTY(x) { \
  363. if (x <= -360.0 || x >= 360.0){\
  364. x = 0;\
  365. }\
  366. }
  367. ROUNDTHREESIXTY(yRot);
  368. ROUNDTHREESIXTY(xRot);
  369. ROUNDTHREESIXTY(zRot);
  370.  
  371. #undef ROUNDTHREESIXTY
  372. #undef OPTION
  373. #undef KEYPAIR
  374. #undef KEYPRESS
  375.  
  376. return;
  377. }

loadObj.h isn't included for it doesn't matter for the rendering code and is rather long.
Last edited by Clockowl; Jul 20th, 2008 at 8:52 pm. Reason: Wrong topic name
Reply With Quote Quick reply to this message  
Join Date: Nov 2005
Posts: 251
Reputation: dwks has a spectacular aura about dwks has a spectacular aura about 
Solved Threads: 25
dwks's Avatar
dwks dwks is offline Offline
Posting Whiz in Training

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #2
Jul 22nd, 2008
My only suggestion is to try a profiler so that you can see exactly where your program is spending all of its time. If you have access to the code from the other program, profiling it as well might be enlightening.

If you're using a Windows port of GCC like MinGW, you already have a profiler: gprof. Google it for details. I'm sure the Microsoft compilers come with one too, but I don't know what it is.
dwk

Seek and ye shall find.

"Only those who will risk going too far can possibly find out how far one can go."
-- TS Eliot.

"I have not failed. I've just found 10,000 ways that won't work."
-- Thomas Alva Edison

"The only real mistake is the one from which we learn nothing."
-- John Powell
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 371
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #3
Jul 22nd, 2008
Gmon.out doesn't contain any useful info, all the times are zero. I'm using it from Code::Blocks on my Windows XP x64 machine.

Like this btw:

  1. Flat profile:
  2.  
  3. Each sample counts as 0.01 seconds.
  4. no time accumulated
  5.  
  6. % cumulative self self total
  7. time seconds seconds calls Ts/call Ts/call name
  8. 0.00 0.00 0.00 1926 0.00 0.00 _RenderScene
  9. 0.00 0.00 0.00 1 0.00 0.00 _WinMain@16
  10. 0.00 0.00 0.00 1 0.00 0.00 _initGL
  11. 0.00 0.00 0.00 1 0.00 0.00 _loadObj
Last edited by Clockowl; Jul 22nd, 2008 at 8:15 pm.
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 371
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #4
Jul 22nd, 2008
Strange, when I run Gprof from the command line, seconds do show up, but it doesn't seem to be compatible with winmain instead of main.

  1. Each sample counts as 0.01 seconds.
  2. % cumulative self self total
  3. time seconds seconds calls ms/call ms/call name
  4. 91.30 0.63 0.63 1 630.00 670.00 loadObj
  5. 5.80 0.67 0.04 297473 0.00 0.00 countSpaces
  6. 1.45 0.68 0.01 isspace
  7. 1.45 0.69 0.01 malloc
  8. 0.00 0.69 0.00 2093 0.00 0.00 RenderScene
  9. 0.00 0.69 0.00 1 0.00 0.00 ChangeSize
  10. 0.00 0.69 0.00 1 0.00 0.00 MySetPixelFormat
  11. 0.00 0.69 0.00 1 0.00 0.00 WinMain@16
  12. 0.00 0.69 0.00 1 0.00 670.00 initGL

Well, I was rewriting it to GLUT anyway. Thanks for the trouble. Suggestions on how to improve the above code are still welcome of course...
Last edited by Clockowl; Jul 22nd, 2008 at 8:17 pm.
Reply With Quote Quick reply to this message  
Join Date: Dec 2006
Posts: 241
Reputation: ssharish2005 is on a distinguished road 
Solved Threads: 20
ssharish2005's Avatar
ssharish2005 ssharish2005 is offline Offline
Posting Whiz in Training

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #5
Jul 23rd, 2008
>Well, I was rewriting it to GLUT anyway. Thanks for the trouble. Suggestions on how to improve the above code are still welcome of course...

Perhaps, placing all your macros definition at the top the code would make it more be neat and professional. That was from a quite glance. That’s a huge lot code!

ssharish
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 371
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #6
Jul 24th, 2008
Erm.. well now I created them right before they are used, and undefined them right after that.. That's neat I think? They are placed where they are used. That way you don't have to scroll up to view it's implementation.

Agreed nonetheless that the code is mess and it could be cleaned up more. But I don't think the macros are that disturbing.

On a sidenote: How do I get gprof to work with C++ using GLUT and threading? Hahaha.. it doesn't display times now even when I run from the console.. I'm downloading VTune as we speak, but I'd like gprof to work, being free and all.
Last edited by Clockowl; Jul 24th, 2008 at 6:50 pm.
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 334
Reputation: Prabakar is on a distinguished road 
Solved Threads: 29
Prabakar's Avatar
Prabakar Prabakar is offline Offline
Posting Whiz

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #7
Jul 25th, 2008
Please attach the loadObj.h file. I know I can't help you, but I believe I can learn from you.
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 371
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #8
Jul 25th, 2008
Hey, of course. It's pretty straightforward tho, only loading vertices, faces and normals, but not polygons and other things (like textures for instance).

The main bottleneck is I/O: sscanf. The only way I see to speed this program up is to:

Multithread it

Store the .obj files as binary data instead of their ASCII representation, so you won't have to use scanf anymore.

loadObj.c
  1. #include <stdio.h> //obvious
  2. #include <stdlib.h> //malloc and such
  3. #include <string.h> //memory copy stuff
  4. #include <time.h> //time stuff, ofc.
  5. #include <ctype.h> //isspace, isdigit
  6. #include <math.h> //only for fabs
  7.  
  8. #define TIMEELAPSED {printf("\tTime elapsed: %lu\n", (clock() - startTime)*1000 / CLOCKS_PER_SEC);}
  9.  
  10. //this is in BowViceJet.c
  11. void dbgError(char *msg);
  12.  
  13. int countSpaces(char *str){
  14. int cnt = 0;
  15. while(*str != '\0'){
  16. if(*str == ' ') cnt++;
  17. str++;
  18. }
  19.  
  20. //remove trailing spaces
  21. str--;
  22. while(isspace(*str)){
  23. if(*str == ' ') cnt--;
  24. str--;
  25. }
  26.  
  27. return cnt;
  28. }
  29.  
  30. int loadObj(const char const *loc,\
  31. float **retvertices, float **retgouraudnormals,\
  32. int **rettriangleindex, int **retquadindex,\
  33. int *quadcount, int *trianglecount){
  34. float *vertices, *gouraudnormals;
  35. int *triangleindex, *quadindex;
  36. float *normals, *verttext;
  37. int *trianglenormals, *quadnormals;
  38.  
  39. clock_t startTime = clock();
  40. int fileSize = 0;
  41. int n, i, j;
  42. printf("Opening file: %s\n", loc);
  43.  
  44. FILE *pFile = fopen(loc, "r");
  45. if(pFile == NULL){
  46. dbgError("fopen()");
  47. exit(1);
  48. }
  49.  
  50. fseek(pFile, 0, SEEK_END);
  51. fileSize = ftell(pFile);
  52. rewind(pFile);
  53.  
  54. char *data = (char*) calloc(sizeof(char), fileSize + 1);
  55.  
  56. fread(data, 1, fileSize, pFile);
  57. if(ferror(pFile)){
  58. dbgError("fread()");
  59. exit(1);
  60. }
  61.  
  62. fclose(pFile);
  63.  
  64. printf("Done reading, parsing file now.\n");
  65. TIMEELAPSED
  66.  
  67. printf("Removing #IND if there...");
  68. char *pIND = data;
  69. n = 0;
  70. while(1){
  71. pIND = strstr(pIND, "#IND");
  72. if(pIND != NULL){
  73. memcpy(pIND, "0000", sizeof(char) * 4);
  74. n++;
  75. }
  76. else break;
  77. }
  78. printf("Removed %d #INDs\n", n);
  79. TIMEELAPSED
  80.  
  81. printf("Counting lines and determining maximum length...");
  82. int maxLen, lenCount;
  83. int lines;
  84.  
  85. for (i = lines = lenCount = maxLen = 0; i <= fileSize; i++){
  86. if (data[i] == '\n'){
  87. lines++;
  88. lenCount++;
  89. if(lenCount > maxLen) maxLen = lenCount;
  90. lenCount = 0;
  91. }
  92. lenCount++;
  93. }
  94.  
  95. printf("Counted %d lines, maximum length: %d\n", lines, maxLen);
  96. TIMEELAPSED
  97.  
  98. printf("Allocating %d strings of %d chars...", lines, maxLen);
  99. char **parsedText = (char**) calloc(sizeof(char*), lines);
  100. for(n = 0; n < lines; n++){
  101. parsedText[n] = (char*) malloc(sizeof(char) * maxLen);
  102. if (parsedText[n] == NULL){
  103. printf("Malloc failed to allocate %d bytes for parsedText[%d].\n", maxLen, n);
  104. return -1;
  105. }
  106. }
  107. printf("Done\n");
  108. TIMEELAPSED
  109.  
  110. printf("Reading in 2D array...");
  111. for(i = n = j = 0; n < lines; i++){
  112. if(data[i] == '\n'){
  113. parsedText[n][j] = '\0';
  114.  
  115. n++;
  116. j = 0;
  117. //puts(parsedText[n]);
  118. continue;
  119. }
  120. //printf("parsedText[%d][%d] = textTree[%d] = %c\n", n, j, i, data[i]);
  121. parsedText[n][j] = data[i];
  122. j++;
  123. }
  124. printf("Done\n");
  125. TIMEELAPSED
  126.  
  127. //free the data, we don't need it anymore since it's stored in parsedText
  128. free(data);
  129.  
  130. /* for(i = 0; i < lines; i++){
  131.   puts(parsedText[i]);
  132.   } */
  133.  
  134. printf("Counting...");
  135.  
  136. int vertlines, normallines, facelines, texturelines;
  137. vertlines = normallines = facelines = texturelines = 0;
  138.  
  139. unsigned int faceverts, maxFaceverts, trianglecnt, quadcnt;
  140. faceverts = maxFaceverts = trianglecnt = quadcnt = 0;
  141.  
  142. //stores for every face line how many verts it has.
  143. int *facevertcnt = calloc(sizeof(int), lines);
  144. for(i = 0; i < lines; i++){
  145. if(parsedText[i][0] == '#') continue;
  146.  
  147. if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){
  148. vertlines++;
  149. }
  150.  
  151. else if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){
  152. normallines++;
  153. }
  154.  
  155. else if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){
  156. facelines++;
  157. for(n = 2; !isdigit(parsedText[i][n]); n++);
  158. faceverts = countSpaces(&parsedText[i][n]);
  159. if(faceverts == 2){
  160. trianglecnt++;
  161. //printf("triangle: %s\n", parsedText[i]);
  162. }
  163. else if(faceverts == 3){
  164. quadcnt++;
  165. //printf("quad: %s", parsedText[i]);
  166. }
  167. if(faceverts > maxFaceverts) maxFaceverts = faceverts;
  168. facevertcnt[i] = faceverts;
  169. //getchar();
  170. }
  171.  
  172. else if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){
  173. texturelines++;
  174. }
  175. }
  176. int vertvals = vertlines * 3;
  177. int normalvals = normallines * 3;
  178. int texturevals = texturelines * 2;
  179. int triangleverts = trianglecnt * 3;
  180. int quadverts = quadcnt * 4;
  181.  
  182. *trianglecount = trianglecnt;
  183. *quadcount = quadcnt;
  184.  
  185. printf("Counted:\n\t%d vertices\n\t%d normals\n\t%d faces (%d triangles, %d quads)\n", vertlines, normallines, facelines, trianglecnt, quadcnt);
  186. TIMEELAPSED
  187. if(maxFaceverts > 4){
  188. printf("WARNING:\n Model won't be imported correctly due to polygons with more than 4 vertices.\n");
  189. }
  190.  
  191. printf("Allocating memory for data...");
  192. vertices = calloc(sizeof(float), vertvals);
  193. normals = calloc(sizeof(float), normalvals);
  194. verttext = calloc(sizeof(float), texturevals);
  195. triangleindex = calloc(sizeof(int), triangleverts);
  196. trianglenormals = calloc(sizeof(int), triangleverts);
  197.  
  198. quadindex = calloc(sizeof(int), quadverts);
  199. quadnormals = calloc(sizeof(int), quadverts);
  200. if(vertices == NULL || normals == NULL || verttext == NULL || triangleindex == NULL || trianglenormals == NULL || quadindex == NULL || quadnormals == NULL){
  201. printf("Failed to allocate enough memory, exiting...\n");
  202. return -1;
  203. }
  204.  
  205.  
  206. int vertcount, normalcount, textcount, tricnt, quacnt;
  207.  
  208. printf("Done\n");
  209. TIMEELAPSED
  210.  
  211. printf("Reading in data...");
  212. for(vertcount = normalcount = textcount = tricnt = quacnt = i = 0; i < lines; i++){
  213. //comment
  214. if(parsedText[i][0] == '#') continue;
  215. if(parsedText[i][0] == ' ') continue;
  216.  
  217. //vertex
  218. if(vertlines)
  219. if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){
  220. sscanf(&parsedText[i][2], "%f%f%f", (vertices+vertcount), (vertices+vertcount+1), (vertices+vertcount+2));
  221. vertcount += 3;
  222. }
  223.  
  224. //normal
  225. if(normallines)
  226. if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){
  227. sscanf(&parsedText[i][2], "%f%f%f", (normals+normalcount), (normals+normalcount+1), (normals+normalcount+2));
  228. normalcount += 3;
  229. }
  230.  
  231. //texture
  232. if(texturelines)
  233. if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){
  234. sscanf(&parsedText[i][2], "%f%f", (verttext+textcount), (verttext+textcount+1));
  235. textcount += 2;
  236. }
  237.  
  238. //faces
  239. if(trianglecnt || quadcnt)
  240. if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){
  241. if(facevertcnt[i] == 2){
  242. //skip all leading spaces
  243. for(n = 2; isspace(parsedText[i][n]); n++);
  244. //read in the vertexnr
  245. sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt));
  246.  
  247. if(normallines){
  248. //skip 2 slashes
  249. for(; parsedText[i][n] != '/'; n++); n++;
  250. for(; parsedText[i][n] != '/'; n++); n++;
  251. //read in the normalnr
  252. sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt));
  253. }
  254.  
  255. for(;!isspace(parsedText[i][n]); n++);
  256. sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+1));
  257. n++;
  258.  
  259. if(normallines){
  260. //skip 2 slashes
  261. for(; parsedText[i][n] != '/'; n++); n++;
  262. for(; parsedText[i][n] != '/'; n++); n++;
  263. //read in the normalnr
  264. sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+1));
  265. }
  266.  
  267. for(;!isspace(parsedText[i][n]); n++);
  268. sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+2));
  269.  
  270. if(normallines){
  271. //skip 2 slashes
  272. for(; parsedText[i][n] != '/'; n++); n++;
  273. for(; parsedText[i][n] != '/'; n++); n++;
  274. //read in the normalnr
  275. sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+2));
  276. }
  277. for(j = 0; j < 3; j++){
  278. //-4 on line 4 becomes 0.
  279. if(triangleindex[tricnt+j] < 0){
  280. triangleindex[tricnt+j] = i - triangleindex[tricnt+j];
  281. }
  282. else{
  283. triangleindex[tricnt+j]--;
  284. trianglenormals[tricnt+j]--;
  285. }
  286. }
  287.  
  288. tricnt += 3;
  289. }
  290. if(facevertcnt[i] == 3){
  291. //skip all leading spaces
  292. for(n = 2; isspace(parsedText[i][n]); n++);
  293. sscanf(&parsedText[i][n], "%d", (quadindex+quacnt));
  294.  
  295. if(normallines){
  296. //skip 2 slashes
  297. for(; parsedText[i][n] != '/'; n++); n++;
  298. for(; parsedText[i][n] != '/'; n++); n++;
  299. //read in the normalnr
  300. sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt));
  301. }
  302.  
  303. for(;!isspace(parsedText[i][n]); n++);
  304. sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+1));
  305. n++;
  306.  
  307. if(normallines){
  308. //skip 2 slashes
  309. for(; parsedText[i][n] != '/'; n++); n++;
  310. for(; parsedText[i][n] != '/'; n++); n++;
  311. //read in the normalnr
  312. sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+1));
  313. }
  314.  
  315. for(;!isspace(parsedText[i][n]); n++);
  316. sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+2));
  317. n++;
  318.  
  319. if(normallines){
  320. //skip 2 slashes
  321. for(; parsedText[i][n] != '/'; n++); n++;
  322. for(; parsedText[i][n] != '/'; n++); n++;
  323. //read in the normalnr
  324. sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+2));
  325. }
  326.  
  327. for(;!isspace(parsedText[i][n]); n++);
  328. sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+3));
  329.  
  330. if(normallines){
  331. //skip 2 slashes
  332. for(; parsedText[i][n] != '/'; n++); n++;
  333. for(; parsedText[i][n] != '/'; n++); n++;
  334. //read in the normalnr
  335. sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+3));
  336. }
  337. for(j = 0; j < 4; j++){
  338. //-4 on line 4 becomes 0.
  339. if(quadindex[quacnt+j] < 0){
  340. quadindex[quacnt+j] = i - quadindex[quacnt+j];
  341. }
  342. quadindex[quacnt+j]--;
  343. quadnormals[quacnt+j]--;
  344. }
  345.  
  346. quacnt += 4;
  347. }
  348. }
  349. }
  350. printf("Done\n");
  351. TIMEELAPSED
  352.  
  353. if(normallines){
  354. printf("Calculating Gouraud normals for each vertex...");
  355. gouraudnormals = calloc(sizeof(float), vertvals);
  356. float normalx, normaly, normalz;
  357. if(trianglecnt != 0){
  358. //printf("::DBG:: calcing trianglenormals\n");
  359. for(i = 0; i < triangleverts; i++){
  360. //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", triangleindex[i]*3, normalvals, trianglenormals[i]*3);
  361. normalx = normals[trianglenormals[i]*3];
  362. normaly = normals[trianglenormals[i]*3+1];
  363. normalz = normals[trianglenormals[i]*3+2];
  364.  
  365. gouraudnormals[triangleindex[i]*3] += normalx;
  366. gouraudnormals[triangleindex[i]*3+1] += normaly;
  367. gouraudnormals[triangleindex[i]*3+2] += normalz;
  368. }
  369. }
  370.  
  371. if(quadcnt != 0){
  372. //printf("::DBG:: calcing quadnormals\n");
  373. for(i = 0; i < quadverts; i++){
  374. //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", quadindex[i]*3, vertvals, quadnormals[i]*3);
  375. normalx = normals[quadnormals[i]*3];
  376. normaly = normals[quadnormals[i]*3+1];
  377. normalz = normals[quadnormals[i]*3+2];
  378.  
  379. gouraudnormals[quadindex[i]*3] += normalx;
  380. gouraudnormals[quadindex[i]*3+1] += normaly;
  381. gouraudnormals[quadindex[i]*3+2] += normalz;
  382. }
  383. }
  384. printf("Done\n");
  385. TIMEELAPSED
  386.  
  387. printf("Normalizing normals...");
  388. for(i = 0; i < normalvals; i += 3){
  389. normalx = fabs(gouraudnormals[i]);
  390. normaly = fabs(gouraudnormals[i+1]);
  391. normalz = fabs(gouraudnormals[i+2]);
  392.  
  393. float max = normalx;
  394. if (normaly > max) max = normaly;
  395. if (normalz > max) max = normalz;
  396.  
  397. //normalize
  398. if(max != 0){
  399. gouraudnormals[i] /= max;
  400. gouraudnormals[i+1] /= max;
  401. gouraudnormals[i+2] /= max;
  402. }
  403. }
  404.  
  405. printf("Done\n");
  406. TIMEELAPSED
  407. }
  408. else{
  409. printf("No normals detected! This version doesn't calculate normals, too lazy. :(\n");
  410. }
  411.  
  412. /* for(n = 0; n < vertvals; n += 3){
  413.   printf("v %f %f %f\n", vertices[n], vertices[n+1], vertices[n+2]);
  414.   } */
  415.  
  416.  
  417. /* for(n = 0; n < normalvals; n += 3){
  418.   printf("vn[%d] %f %f %f\n", n/3, normals[n], normals[n+1], normals[n+2]);
  419.   } */
  420.  
  421. /*
  422.   for(n = 0; n < texturevals; n += 2){
  423.   printf("vt %f %f\n", verttext[n], verttext[n+1]);
  424.   } */
  425.  
  426. /*
  427.   for(n = 0; n < triangleverts; n += 3){
  428.   printf("triangle: %d %d %d\n\t"
  429.   "Normals: %d %d %d\n",\
  430.   triangleindex[n], triangleindex[n+1], triangleindex[n+2],\
  431.   trianglenormals[n], trianglenormals[n+1], trianglenormals[n+2]);
  432.   } */
  433.  
  434. /* for(n = 0; n < quadverts; n += 4){
  435.   printf("Quad: %d %d %d %d\n\t"
  436.   "Normals: %d %d %d %d\n",\
  437.   quadindex[n], quadindex[n+1], quadindex[n+2], quadindex[n+3],\
  438.   quadnormals[n], quadnormals[n+1], quadnormals[n+2], quadnormals[n+3]);
  439.   } */
  440.  
  441. /* if(normallines)
  442.   for(n = 0; n < vertlines; n++){
  443.   printf("Normals for v[%d]: %f %f %f\n", n, gouraudnormals[n*3], gouraudnormals[n*3+1], gouraudnormals[n*3+2]);
  444.   } */
  445.  
  446. printf("File succesfully loaded, returning.\n");
  447.  
  448. TIMEELAPSED
  449. *retvertices = vertices;
  450. *retgouraudnormals = gouraudnormals;
  451. *rettriangleindex = triangleindex;
  452. *retquadindex = quadindex;
  453. return 0;
  454. }
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 334
Reputation: Prabakar is on a distinguished road 
Solved Threads: 29
Prabakar's Avatar
Prabakar Prabakar is offline Offline
Posting Whiz

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #9
Jul 26th, 2008
Thanks for the code, I guess It will take me sometime to understand the code.
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 371
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Optimizing OpenGL (SwapBuffer being slow)

 
0
  #10
Jul 26th, 2008
Feel free to ask questions, my email and msn in in your inbox.
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:



Other Threads in the C Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC