Nanashi-softプログラマ専用PS3 Linux SDL


◇PS3 Linux SDLでプログラミング -どのくらいの描画が可能か?-

現状は RSXの仕様が隠蔽されていて、実質フレームバッファしか使用できません(2007/02現在)
「それだと何もできない」と思っている人が多いので、どのくらいダメなの? 本当にダメなの? という所を検証してみました

○雛形

まずはベンチマークを取る為の雛形を作成しました
1秒間に何回描画できるのか? を測ります。それが一番分かり易いでしょう
ちなみに、この雛形状態だと 231298fpsでしたw

#include "SDL.h"

int main(int args,char *argp[]){
  //初期化
  if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0){
    return -1;
  }

  SDL_Surface *screen=SDL_SetVideoMode(1920,1080,32,SDL_SWSURFACE);
  if(screen == NULL){
    SDL_Quit();
    return -1;
  }

  int done = 0;
  SDL_Event event;

  int fps=0;

  Uint32 t1=SDL_GetTicks();
  while(!done){
    while(SDL_PollEvent(&event)){
      switch(event.type){
      case SDL_QUIT:
        done = 1;
        break;
      case SDL_KEYDOWN:
        if(event.key.keysym.sym == SDLK_ESCAPE){
          done = 1;
        }
        break;
      }
    }

//ここに処理を追加して変化を見る

    if(SDL_GetTicks() < t1 + 1000){
      fps++;
    }
    else{
      printf("fps=%d\n", fps);
      fps=0;
      t1=SDL_GetTicks();
    }
  }

  SDL_Quit();
}

○裏画面をそのまま表示してみる

RGB(24bit)で羅列したデータを、直接描画して測ってみます
グローバル変数にこの裏画面を生成して、SDL_CreateRGBSurfaceFromでサーフェスにします

~
unsigned char gUra[1920*1080*3];//裏画面
~
int main(int args,char *argp[]){
~
  while(!done){
~
//ここに処理を追加して変化を見る
    SDL_Surface *bitmap = SDL_CreateRGBSurfaceFrom((void *)gUra,1920,1080,24,1920*3,0xff0000,0xff00,0xff,0);
    SDL_BlitSurface(bitmap,NULL,screen,NULL);
    SDL_UpdateRect(screen,0,0,0,0);
~

これを計測すると 5fpsでしたよ(*'-')

○フレームバッファにフォーマットを合わせてみる

うはw 5fpsじゃ何も作れないよorz
……と思ったら、そこで終わりです

このような際物機器では、自動で最適化される事がありません
自力で最適化して、速度を上げていくのが常識なのです

データをそのまま渡してしまった事が間違いだと思うので、今度はフレームバッファのフォーマットに自力で合わせてから送ってみます

unsigned char gUra[1920*1080*3];//裏画面
Uint32 pix[1920*1080];//ワーク用画面
~
int main(int args,char *argp[]){
~
//ここに処理を追加して変化を見る
    int x, y;

    Uint32 *pixp = pix;
    unsigned char *gUrap=gUra;
    for(y=0; y < 1080; y++){
      for(x=0; x < 1920; x++){
        unsigned int r = *gUrap++;
        unsigned int g = *gUrap++;
        unsigned int b = *gUrap++;
        *pixp++ = (r << 16) + (g << 8) + b;
      }
    }
    SDL_Surface *bitmap = SDL_CreateRGBSurfaceFrom((void *)pix,1920,1080,32,1920*3,0xff0000,0xff00,0xff,0);
    SDL_BlitSurface(bitmap,NULL,screen,NULL);
    SDL_UpdateRect(screen,0,0,0,0);
~

このままだとやっぱり 5fpsです

コンパイラオプションに最適化を付けると、劇的にスピードアップします
gcc -O2 -o 「拡張子無しファイル名」「ファイル名」 `sdl-config --cflags --libs`
そうすると、25fps出ました(^_^)

更に、この場合SDL_SWSURFACEを SDL_HWSURFACEにするだけで 36fpsにアップします
blitが高速化される為だと思われます

○裏画面もフレームバッファと同じフォーマットにしてみる

ふと思いました
裏画面を最初からフレームバッファと同じフォーマットにしておいたらどうでしょう?
PS3はハード的に固定なので、専用であればそれで良いはずです

Uint32 gUra[1920*1080*4];//裏画面
~
int main(int args,char *argp[]){
~
//ここに処理を追加して変化を見る
    SDL_Surface *bitmap = SDL_CreateRGBSurfaceFrom((void *)gUra,1920,1080,32,1920*3,0xff0000,0xff00,0xff,0);
    SDL_BlitSurface(bitmap,NULL,screen,NULL);
    SDL_UpdateRect(screen,0,0,0,0);

裏画面と実画面の構造が同じなので、変換する必要が無い
こうすると 105fpsでました!

更に、グローバルでは無くヒープの方に置いて実験してみたところ……

int main(int args,char *argp[]){
Uint32 *gUra=(Uint32*)malloc(1920*1080*4);//ワーク用画面
~
while(!done){
~
//ここに処理を追加して変化を見る
    SDL_Surface *bitmap = SDL_CreateRGBSurfaceFrom((void *)gUra,1920,1080,32,1920*3,0xff0000,0xff00,0xff,0);
    SDL_BlitSurface(bitmap,NULL,screen,NULL);
    SDL_UpdateRect(screen,0,0,0,0);

そうすると 229fpsでました(*'-')

○まとめ

以上の検証より、SDLでは、実画面に合わせたフォーマットのデータを扱う事によりスピードアップすると言うことが分かりました
逆に言えば、独自フォーマットを使用すると劇的に速度低下を起こすと言う事ですので、注意が必要ですね

全グラフィックをハードウェアサーフェス上に置いて、それを表示したらもっと速いでしょう
フルHD(1920×1080画面で毎秒60コマ表示)も夢では無いかも知れませんよ
ぜひ、みなさんもチャレンジしてみて下さい


TOPプログラマ専用PS3 Linux SDL