微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

有没有办法强制linux framebuffer立即显示帧?

如何解决有没有办法强制linux framebuffer立即显示帧?

我正在用 C++ 制作一个视频播放器,它在 linux 帧缓冲区上显示视频。帧在更新后不直接可见,但只有在 tty 更新后才可见(例如,光标闪烁或我按住某个键)。

我不认为 cpu 会变慢/做太多事情,因为没有一个内核有 100% 的使用率,而程序最多使用 30% 的 cpu

如果我运行 htop,它将光标隐藏在 tty 上,帧缓冲区只会在 htop 刷新时更新(每 1.5 秒)。

我在带有双核 Intel Core i3-8145U 和集成显卡(Intel UHD Graphics 620) 带有 i915 驱动程序。

有没有办法告诉帧缓冲区更新? 我尝试使用 fsync,但它没有做任何事情。

在 tty 上打印换行符会使 tty 更新,但这似乎没有必要。 我尝试了 ioctl(tty1_fd,KDSETMODE,KD_GRAPHICS),但这会冻结输出,我必须通过 ssh 登录并运行 ioctl(tty1_fd,KD_TEXT) 才能对笔记本电脑执行任何操作或查看更新的帧缓冲区。

这只会影响我的笔记本电脑。如果我在配备双核 AMD E-350 和(集成?)Advanced Micro Devices [AMD/ATI] Wrestler [Radeon HD 6310] 显卡和 linux 5.11.10-gentoo-x86_64 的 PC 上运行它,一切正常。

This framebuffer example 也有同样的问题。

我尝试用 mplayer 播放视频,但它也不起作用。 如果我转到 tty3 并使用 mplayer -vo fbdev2:/dev/fb0 video.mp4 运行它,视频将正常播放而没有任何延迟。 如果我切换到 tty4,视频(不是声音)会开始卡顿。 看起来它仅在 tty 更新帧缓冲区后才显示帧缓冲区的内容(即光标闪烁或写入新字符) 它适用于 tty3,因为 mplayer 在每次屏幕更新后写入当前时间,这将使帧缓冲区更新。

最小示例:

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <chrono>
#include <thread>
#include <sys/mman.h>

constexpr size_t WIDTH = 1920; // framebuffer width (in pixels)
constexpr size_t HEIGHT = 1080; // framebuffer height (in pixel)
constexpr size_t BYTES_PER_PIXEL = 4; // bytes per pixel (bgra)
constexpr size_t MEM_WIDTH = WIDTH * BYTES_PER_PIXEL; // framebuffer width in memory
constexpr size_t FRAME_SIZE = MEM_WIDTH * HEIGHT; // size of one frame
constexpr size_t FPS = 24; // framerate
static constexpr size_t NSPF = FPS ? std::nano::den / (FPS * std::nano::num) : 0; // nanoseconds per frame
static constexpr std::chrono::nanoseconds SLEEP_DURATION{NSPF};

int fb_fd; // framebuffer filedescriptor
uint8_t *fb_mem; // pointer to mmaped framebuffer

static void set_pixel(size_t x,size_t y,bool black)
{
    auto *pixel = &fb_mem[MEM_WIDTH * y + x * BYTES_PER_PIXEL];
    std::fill_n(pixel,4,black ? 0 : 255);
}

int main()
{
    fb_fd = open("/dev/fb0",O_RDWR);
    fb_mem = static_cast<uint8_t *>(mmap(nullptr,FRAME_SIZE,PROT_READ | PROT_WRITE,MAP_SHARED,fb_fd,0));
    size_t x = 0;
    size_t y = 100;
    bool black = false;
    while (true)
    {
        for (size_t _x = x; x < _x + 10; x++)
            set_pixel(x,y,black);
        if (x >= WIDTH)
        {
            x %= WIDTH; // go back to the beginning side of the line
            black = !black;
        }
        std::this_thread::sleep_for(SLEEP_DURATION); // wait for the next frame
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。