Правильная двойная буферизация с помощью фреймбуфера linux

Мне интересно, как правильно удвоить буфер кадра, чтобы избежать разрывов. Я провел много исследований по этой теме и, похоже, ничего не нашел.

Я пробовал FBIO_WAITFORVSYNC. Но по этой теме: Как запросить фазу Vsync в Linux кажется что это не сработает.

Я также пробовал использовать FBIOGET_VSCREENINFO и FBIOPAN_DISPLAY для этого потока: графика фреймбуфера Linux и VSync . Но это не удалось из-за ошибки, обсуждаемой в этом потоке: ошибка неверного аргумента при установке yres_virtual в fb_var_screeninfo

В этом потоке было предложено использовать другой драйвер (vesafb) для устранения ошибки. Мне удалось установить uvesafb на моем компьютере, но ошибка «Недопустимый аргумент» не исчезла.

Я также пробовал просто создать буфер большего размера по предложению этого человека: http://betteros.org/tut/graphics1.php#doublebuffer, но mmap продолжает возвращать -1.

Я также попытался реализовать обсуждаемое здесь решение: https://pyra-handheld.com/boards/threads/my-frustrating-experiences-with-dev-fb.21062/. Однако поток умер без публикации фактического решения, и я сомневаюсь в эффективности замены аппаратных адресов (или если это вообще возможно).

Любая помощь будет принята с благодарностью по этой теме!

По запросу вот код, который я в идеале хотел бы приступить к работе:

fb0 = open("/dev/fb0", O_RDWR);
    if(fb0 == 0)
        error("Could not open framebuffer located in /dev/fb0!");

    if (ioctl(fb0, FBIOGET_FSCREENINFO, &screeninfo_fixed) == -1)
        error("Could not retrive fixed screen info!");

    if (ioctl(fb0, FBIOGET_VSCREENINFO, &screeninfo_var) == -1)
        error("Could not retrive variable screen info!");

    screeninfo_var.xres_virtual = screeninfo_var.xres;
    screeninfo_var.yres_virtual = screeninfo_var.yres * 2;
    screeninfo_var.width = screeninfo_var.xres;
    screeninfo_var.height = screeninfo_var.yres;
    screeninfo_var.xoffset = 0;
    screeninfo_var.yoffset = 0;

    if (ioctl(fb0, FBIOPUT_VSCREENINFO, &screeninfo_var) == -1)
        error("Could not set variable screen info!");

Это всегда будет напечатать "Не удалось установить переменную информацию об экране!" из-за некоторых проблем с увеличением размера виртуального буфера кадра.


person ktb92677    schedule 04.04.2018    source источник
comment
Отправьте минимальный воспроизводимый пример, чтобы мы могли помочь вам определить основную причину проблемы.   -  person user3629249    schedule 04.04.2018
comment
Я также добавил образец кода.   -  person ktb92677    schedule 05.04.2018
comment
относительно: fb0 = open("/dev/fb0", O_RDWR); if(fb0 == 0) error("Could not open framebuffer located in /dev/fb0!"); Функция: open() всегда возвращает значение ‹0 при сбое (тогда код должен вызывать perror(), поэтому текстовая причина, по которой система считает, что функция не выполнена, записывается в stderr 0, является допустимым возвращаемым значением (хотя код должен это значение видно только в том случае, если stdin был закрыт   -  person user3629249    schedule 05.04.2018
comment
когда вызов open() завершается неудачно, после отображения сообщения об ошибке код должен вызывать exit(), поскольку file descriptor недоступен для обеспечения доступа к файлу.   -  person user3629249    schedule 05.04.2018
comment
Я ценю ответы ... но они вообще не касаются вопроса. Мой вопрос касается двойной буферизации с буфером кадра ... а не функции open ()   -  person ktb92677    schedule 05.04.2018
comment
В комментариях мы либо просим разъяснений, либо указываем на проблемы, которые НЕ являются проблемой, о которой спрашивают.   -  person user3629249    schedule 06.04.2018


Ответы (1)


Способ, которым я решил проблему двойной буферизации для фреймбуфера в Linux, - это использование отдельного заднего буфера, выделенного с помощью mmap для того же размера экрана:

bbp = mmap(0, screensize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

(где screensize = vinfo.yres_virtual * finfo.line_length;)

Затем запишите все изменения в этот задний буфер, и после того, как все записи будут завершены, скопируйте весь задний буфер в местоположение указателя основного фреймбуфера, используя, скажем, функцию update ():

memcpy(fbp, bbp, screensize);

У вас также может быть функция updateRect (), которая копирует только заданную область. Эта логика отлично работает на моей платформе x64 gnu / linux.

person KVS    schedule 12.08.2018
comment
Не могли бы вы попробовать воспроизвести видео, используя этот алгоритм двойной буферизации? Вы увидите, что экран действительно рвется. Этот базовый алгоритм двойной буферизации недостаточно хорош, чтобы избежать разрывов экрана с такими вещами, как видео в буфере кадра. Пожалуйста, попробуйте libdri, если вы хотите избавиться от разрывов экрана при низкоуровневом программировании графики. - person ktb92677; 13.08.2018