61 lines
1.6 KiB
C++
61 lines
1.6 KiB
C++
#include "framebuffer.hpp"
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/fb.h>
|
|
#include <cstring>
|
|
|
|
FrameBuffer::FrameBuffer() : _fd(-1), _buffer(nullptr), _width(0), _height(0), _screensize(0) {}
|
|
|
|
FrameBuffer::~FrameBuffer() { release(); }
|
|
|
|
bool FrameBuffer::init(const char* device)
|
|
{
|
|
_fd = open(device, O_RDWR);
|
|
if (_fd < 0) return false;
|
|
|
|
fb_var_screeninfo vinfo;
|
|
if (ioctl(_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) return false;
|
|
|
|
_width = vinfo.xres;
|
|
_height = vinfo.yres;
|
|
_screensize = _width * _height * 2; // RGB565 = 2 bytes/pixel
|
|
|
|
_buffer = (uint16*)mmap(nullptr, _screensize, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, _fd, 0);
|
|
return (_buffer != MAP_FAILED);
|
|
}
|
|
|
|
void FrameBuffer::release()
|
|
{
|
|
if (_buffer && _buffer != MAP_FAILED)
|
|
munmap(_buffer, _screensize);
|
|
if (_fd >= 0) { close(_fd); _fd = -1; }
|
|
_buffer = nullptr;
|
|
}
|
|
|
|
void FrameBuffer::_rgb888_to_rgb565(const uint8* src, uint16* dst, int pixels)
|
|
{
|
|
for (int i = 0; i < pixels; ++i)
|
|
{
|
|
uint8 r = src[i * 3];
|
|
uint8 g = src[i * 3 + 1];
|
|
uint8 b = src[i * 3 + 2];
|
|
dst[i] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
|
}
|
|
}
|
|
|
|
bool FrameBuffer::write(const uint8* rgb888_data, int w, int h)
|
|
{
|
|
if (!_buffer || _buffer == MAP_FAILED) return false;
|
|
|
|
int copy_w = (w < _width) ? w : _width;
|
|
int copy_h = (h < _height) ? h : _height;
|
|
|
|
for (int y = 0; y < copy_h; ++y)
|
|
_rgb888_to_rgb565(rgb888_data + y * w * 3, _buffer + y * _width, copy_w);
|
|
|
|
return true;
|
|
}
|