2016-04-01 21 views
1

Linux çerçeveleyiciden bir çerçeveyi tekrar tekrar çekmeye çalışıyorum, ancak her kare için yaklaşık bir saniye alıyor.Linux Çerçeve Oluşturucu Verimsiz Çerçeve Yakalama

60FPS beklemiyordum, 60FPM'den fazla olmasını umuyordum. Bu normal mi? Açık kaynaklı video sürücüleri kullanıyorum; GPU'm bir AMD 280X ve CPU'm bir 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++; 
     } 
    } 

Benim tam kod here mevcuttur, ancak ben döngüler önemli parçası olduğunu düşünüyorum:

Benim kod şöyle görünür.

#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; 
} 

: (kendi döngünün her vadede çarpma ve bölme gerçekleştirilen olsa bile)

Buna ek olarak, bir pembe her piksel ayarlar this website bir programı çalıştıran çalıştı ve döngü kendisi yalnızca 7ms aldı Çerçevebacker'a yazmak, ondan okumaktan çok daha hızlı mı?

+1

Her döngüde pahalı işlemler (çoğalmalar) yapıyorsunuz; Piksel ve çizgi başına işaretçiyi artırarak onları önlemek. Bunun için x ve y döngülerini değiştirmelisiniz. – ensc

+1

İki öneri: Öncelikle, 'uint32_t' işaretçi yayınlarını kaldırın, kodu okunamaz hale getiriyorlar. Daha sonra, iç döngüde 'if' işaretini kaldırın, havai yükü muhtemelen onu kaydetmeye çalıştığınız süreden daha büyüktür. Son olarak, 'memcpy()' veya GCC tarafından sağlanan hizalanmış değişkenlerden birini kullanın ve bir bütün çizgi kopyalayın, bu da performansı biraz artırmalıdır. Bu, kodunuzun tam olarak nerede zaman harcadığını söyledi? Kodu okudun mu? –

+0

@UlrichEckhardt "uint32_t" işaretçisi kalıbını kaldırdım ve if deyimini "memcpy" ile bir 'memcpy' öğesinden, uint32_t 'boyutuna sahip bir önceki arabellek işaretçisine (verilen, yine de tüm piksel değil, tüm satır) değiştirdim. ve performans yaklaşık olarak eşitti (990 ms). – Vreality

cevap

1

Benim döngü için (denenmemiş) öneri:

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; 
         } 
       } 
     } 
} 

daha fazla optimize etmek istiyorsanız, ekstra bir dosya içine iç x döngü koymak (örneğin inner-x-loop.inc.h) ve edebilirsiniz

gibi dahil
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 numaralı numaraların numaralandırılması, derleyicinin mempcpy() numaralı satırı satır içinde tutmasına izin verir.

+0

allow_memcpy nedir? Kodunuzu test etmek için bir tanesini ayarladım. Herhangi bir nedenle, gcc, string.h' dahil ettiğim gerçeğine rağmen örtülü bir işlev olduğundan şikayet ediyor, bu yüzden henüz derlemedim. – Vreality

+0

'allow_memcpy' bir derleme zamanı sabiti olmalıdır (ör. #define allow_memcpy (true)' veya 'statik bool const allow_memcpy = true'). 'mempcpy' gerektirir' _GNU_SOURCE'; Örneğin. '-std = gnu99' ile derleyin ya da el ile tanımlayın. – ensc

+0

Kodunuzu (birkaç [modifikasyon] ile (https://gist.github.com/nashley/63fadf31e8b2f188d6ceeaf6fa11e581)) derledim ve bulduğum herhangi bir diğer uygulamadan daha hızlı olduğu halde 441 ms sürdü. . Kendi makinenizde benzer sonuçlar alıyor musunuz? Kurulumumda sorun olabilir mi? – Vreality