2016-04-01 9 views
1

私はLinuxフレームバッファーからフレームを繰り返し取得しようとしていますが、フレームごとに約2秒かかります。Linuxフレームバッファーの非効率的なフレームグラブ

私は60FPSは期待していませんでしたが、私は60FPM以上を望んでいました。これは正常ですか?私はオープンソースのビデオドライバを使用しています。私のGPUはAMD 280X、私のCPUはAMD 8320 @ 4.4GHzです。

static uint8_t *previous_buffer; 
static uint8_t *fbp; 

static long int location = 0; 
long int screensize = 0; 

int sf = open("/dev/fb0",O_RDWR); 
struct fb_var_screeninfo vinfo; 
struct fb_fix_screeninfo finfo; 

ioctl(sf, FBIOGET_FSCREENINFO, &finfo); 
ioctl(sf, FBIOGET_VSCREENINFO, &vinfo); 

screensize = finfo.smem_len; 

fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, sf, (off_t)0); 

previous_buffer = malloc(screensize); 

bytespp = (vinfo.bits_per_pixel/8); 

for(int x = 0; x < vinfo->xres * bytespp; x+=bytespp) 
    for(int y = 0; y < vinfo->yres * finfo->line_length; y+=finfo->line_length){ 
     //printf("xoff: %d yoff:%d x:%d y:%d\n", xoff, yoff, x, y); 
     location = x + y + off; 
     //printf("Location: %lu\n", location); 
     if(*((uint32_t*)(fbp+location)) != *((uint32_t*)(previous_buffer+location))){ 
      memcpy((fbp+location), (previous_buffer+location), 4); // sizeof(uint32_t) 
      d1++; 
     } 
    } 

私の完全なコードがhere利用可能ですが、私はループが重要な部分だと思います:

私のコードは次のようになります。

#include <linux/fb.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <fcntl.h> 
#include <sys/mman.h> 
#include <sys/ioctl.h> 

inline uint32_t pixel_color(uint8_t r, uint8_t g, uint8_t b, struct fb_var_screeninfo *vinfo) 
{ 
    return (r<<vinfo->red.offset) | (g<<vinfo->green.offset) | (b<<vinfo->blue.offset); 
} 

int main() 
{ 
    struct fb_fix_screeninfo finfo; 
    struct fb_var_screeninfo vinfo; 

    int fb_fd = open("/dev/fb0",O_RDWR); 

    //Get variable screen information 
    ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo); 
    vinfo.grayscale=0; 
    vinfo.bits_per_pixel=32; 
    ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vinfo); 
    ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo); 

    ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo); 

    long screensize = vinfo.yres_virtual * finfo.line_length; 

    uint8_t *fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, (off_t)0); 

    int x,y; 

    for (x=0;x<vinfo.xres;x++) 
     for (y=0;y<vinfo.yres;y++) 
     { 
      long location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + (y+vinfo.yoffset) * finfo.line_length; 
      *((uint32_t*)(fbp + location)) = pixel_color(0xFF,0x00,0xFF, &vinfo); 
     } 

    return 0; 
} 

:(それはそのループの各実行で乗算および除算を実行しても)

さらに、私はピンクに、各画素を設定this websiteからプログラムを実行しようとした、ループ自体のみ7MSを取りましたフレームバッファへの書き込みは、それよりもはるかに速いですか?

+1

各ループ内で高価な操作(乗算)を行っています。ピクセルとラインごとにポインタをインクリメントすることでそれらを避けてください。これのためにxとyのループを入れ替えるべきです。 – ensc

+1

2つの提案:まず、それらの 'uint32_t'ポインタのキャストを取り除くと、コードが読めなくなります。内部ループの 'if'チェックを取り除くと、そのオーバヘッドはおそらくあなたがそれを保存しようとする時よりも大きいでしょう。最後に、 'memcpy()'またはGCCが提供する一式の整列された亜種のうちの一つを使って、行全体をコピーしてください。つまり、あなたのコードはどこで正確に時間を費やしていますか?コードをプロファイルしましたか? –

+0

@UlrichEckhardt 'uint32_t'ポインタのキャストを取り除き、フレームバッファのポインタから' memcpy'を 'uint32_t'のサイズの以前のバッファポインタに置き換えました(与えられた行は全ピクセルではありません) 、性能はほぼ同等(すなわち、990ms)であった。 – Vreality

答えて

1

私のforループ(未テスト)の提案:

void const *start = (fbp + vinfo->yoffset * finfo->line_length + 
        vinfo->xoffset * bytespp); 
void  *out = previous_buffer; 
size_t  xres_bytes = vinfo->xres * bytespp; 
size_t  d_stride = finfo->line_length - xres_bytes; 

if (d_stride == 0 && allow_memcpy) { 
     memcpy(out, start, finfo->line_length * vinfo->yres); 
} else { 
     for (int y = 0; y < vinfo->yres_virtual; ++y) { 
       start += d_stride; 
       if (allow_memcpy) { 
         out = mempcpy(out, start, xres_bytes); 
         start += xres_bytes; 
       } else { 
         /* or do the #include thing below here */ 
         for (int x = 0; x < vinfo->xres_virtual; ++x) { 
           switch (bytesbpp) { 
           case 1: out = mempcpy(out, start, 1); break; 
           case 2: out = mempcpy(out, start, 2); break; 
           case 3: out = mempcpy(out, start, 3); break; 
           case 4: out = mempcpy(out, start, 4); break; 
           default: out = mempcpy(out, start, bytesbpp); break; 
           } 
           start += bytesbpp; 
         } 
       } 
     } 
} 

あなたはさらにそれを最適化したい場合は、あなたが余分なファイル(例えばinner-x-loop.inc.h)にインナーxループを置くことができますし、

のようにそれを含めます
if (bytesbpp == 1) { 
#include "inner-x-loop.inc.h" 
} else if (bytesbpp == 2) { 
#include "inner-x-loop.inc.h" 
} else if (bytesbpp == 3) { 
#include "inner-x-loop.inc.h" 
} else if (bytesbpp == 4) { 
#include "inner-x-loop.inc.h" 
} else 
#include "inner-x-loop.inc.h" 
} 

bytesbppを列挙すると、コンパイラはmempcpy()をインライン化できます。

+0

allow_memcpyとは何ですか?私はあなたのコードをテストするために1に設定しました。何らかの理由で、gccは 'string.h'をインクルードしていたにもかかわらずmempcpyが暗黙の関数であると訴えているので、まだコンパイルできませんでした。 – Vreality

+0

'allow_memcpy'はコンパイル時定数(' #define allow_memcpy(true) 'や' static bool const allow_memcpy = true'など)でなければなりません。 'mempcpy'には' _GNU_SOURCE'が必要です。例えば'-std = gnu99'でビルドするか、手動で定義してください。 – ensc

+0

私はあなたのコードをコンパイルしました(いくつかの[変更](https://gist.github.com/nashley/63fadf31e8b2f188d6ceeaf6fa11e581))、それは441msを要しました。 。自分のマシンでも同様の結果が得られますか?セットアップに問題がありますか? – Vreality

関連する問題