討論區快速選單
知識庫快速選單
掌握Salesforce雲端管理秘訣 程式設計俱樂部Facebook粉絲團 傑米的攝影旅遊筆記
[ 回上頁 ] [ 討論區發言規則 ]
glut 教學 - 計算 frame rate 的正確方法
更改我的閱讀文章字型大小
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/2/23 下午 09:25:31
當我們要比較 3D 程式的效率, frame rate 是一個很重要的資料.

但是, 算 frame rate 也算得正確才有意思呀. 這次, 我就介紹一下如何算 frame rate.

首先, 讀者們, 你要先了解一件事, 現代的顯示卡, 已經不再是純粹把 digital 資料 轉成 analog 資料的低檔硬體, 它, 已經變成了一個 精密 而 架構複雜的系統. 因此, 算 frame rate 時, 也得了解它多一些.

算 frame rate, 最直接的想法, 就是把 display() 重複呼叫器一定的次數, 把 次數 除以 所需時間 就是 frame rate. 但是, 這是不正確的, 因為 glutSwapBuffers() 會等待 顯示器 完成最近一次更新, 才會完結的. 結果, 如果你的程式比 顯示器更新率 跑得更快, 所算出來的 frame rate 再多也只可能是 顯示器更新率. 舉例說, 在顯示器的更新率, 一般是 75 fps, 如上述算 frame rate, 最快也只會是 75 fps.

又說, 如果我們把 glutSwapBuffers() 拿掉, 就不用等待 顯示器 完成更新呀. 但是, 這樣算 frame rate 也不正確. 因為, 顯示卡是有一個指令緩衝的機制, 就是說, 你給 顯示卡 下繪圖指令時, 指令並不會被立即執行, 指令會先儲存在 顯示卡的指令緩衝區, 直到 緩衝區爆滿 或是 被特別地指令 緩衝區內的指令才會被執行. 因此, 只把 glutSwapBuffers() 拿掉, 所算出來的 frame rate, 只反映指令由 主記憶體 傳到 顯示卡緩衝區 的速度而已.

說到這裡, 聰明的讀者們大概也估計到要甚麼做, 就是, 把 glutSwapBuffers() 換成為 強制顯示卡執行指令. 這個指令, 就是 glFinish(). 只要把 glutSwapBuffers() 換成為 glFinish(), 所有繪令指令就會被執行, 又不用被 顯示器更新率 限制. 這樣算出來的 frame rate, 才能有效的反映 3D 程式效能.

好, 我們去寫程式算 frame rate 吧...

作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/2/23 下午 09:27:25
/////////////////////////
// glutTest10.cpp
//
// Created by Gary Ho, ma_hty@hotmail.com, 2006
//


#include <stdio.h>
#include <time.h>

#include "glut.h"

void display();
void keyboard( unsigned char key, int x, int y );

float g_fps( void (*func)(void), int n_frame );

bool finish_without_update = false;

void main()
{
  glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB );
  glutInitWindowSize( 640, 640 );
  glutCreateWindow( "glutTest10" );

  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);

  glutMainLoop();
}

void keyboard( unsigned char key, int x, int y )
{
  switch( key )
  {
    case 'F':
    case 'f':
     finish_without_update = true;
     printf( "%f fps\n", g_fps( display, 100 ) );
     finish_without_update = false;
     break;
  }
}

void display()
{
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     gluPerspective( 20, 1, 0.1, 10 );

    glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(
     0,0,1,
     0,0,0,
     0,1,0 );

    glEnable( GL_LIGHTING );
    glEnable( GL_LIGHT0 );
    glEnable( GL_DEPTH_TEST );
    glutSolidTeapot( .1 );

  if( finish_without_update )
    glFinish();
  else
    glutSwapBuffers();
}

float g_fps( void (*func)(void), int n_frame )
{
  clock_t start, finish;
  int i;
  float fps;

  printf( "Performing benchmark, please wait" );
    start = clock();
    for( i=0; i<n_frame; i++ )
    {
     if( (i+1)%10==0 )
     printf(".");
     func();
    }
    printf( "done\n" );
    finish = clock();

  fps = float(n_frame)/(finish-start)*CLOCKS_PER_SEC;
  return fps;
}
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/2/23 下午 09:32:50
void display()
{
// ...
  if( finish_without_update )
    glFinish();
  else
    glutSwapBuffers();
}

display() function 最後的幾行, 就是用來選擇用 glFinish() 還是用 glutSwapBuffers(), 算 frame rate 時, 我們用 glFinish(), 其他時間我們用 glutSwapBuffers().
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/2/23 下午 09:33:54
非常簡潔的一個程式, 沒什麼要再特別交待了... ...
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/2/23 下午 09:35:16
噢... 忘記了...

按 F 鍵 就會開始算 frame rate, 計算完畢, 結果就會顯示在 console 上.
作者 : dexicule(dexicule)
[ 貼文 1 | 人氣 0 | 評價 20 | 評價/貼文 20 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人ma_hty註記此篇回應為很有道理 2010/9/12 下午 09:52:36
这算是挖坟吗.. 不过我看到第一眼就想说 printf那个"." 绝对不是好事的
从来在for里面printf基本上都是杯具

事实也如此。注释该行 FPS 为4600. 启用该行仅仅只有400而已。

小小的建议
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/9/12 下午 11:57:32
真的要謝謝 dexicule 的建議呢... 以下的修正後的 g_fps() 函數.

float g_fps( void (*func)(void), int n_frame )
{
  clock_t start, finish;
  int i;
  float fps;

  printf( "Performing benchmark, please wait" );
    start = clock();
    for( i=0; i<n_frame; i++ )
    {
     func();
    }
    printf( "done\n" );
    finish = clock();

  fps = float(n_frame)/(finish-start)*CLOCKS_PER_SEC;
  return fps;
}

順帶一提, 這裡的 printf() 無疑是錯了, 不過, 依我的經驗, 它對速度的影響
應該並沒 dexicule 說的那麼大的, 我估計, 這可能因為是 dexicule 的測試程式
是在 debug mode 編譯出來的吧.
 板主 : 白老鼠(Gary)
 > OpenGL - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - OpenGL - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
OpenGL
1 白老鼠(Gary) 2720 
2 CROMAYEN2000 1530 
3 aming 500 
4 東昇 380 
5 PLAYER 120 
6 富伯 110 
7 qq 100 
8 NDark 80 
9 ozzy 60 
10 simula 60 
OpenGL
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.046875