27#include "pedigree_fb.h"
28#include <pedigree/fb.h>
29#include <pedigree/log.h>
37sigset_t terminalSignals() {
39 sigemptyset(&signals);
40 sigaddset(&signals, SIGUSR1);
41 sigaddset(&signals, SIGUSR2);
46Framebuffer::Framebuffer()
57Framebuffer::~Framebuffer() {
60 munmap(m_pFramebuffer, m_FramebufferSize);
62 m_FramebufferSize = 0;
71Framebuffer::FrameGuard::FrameGuard(
const Framebuffer& framebuffer)
72 : m_Masked(false), m_Active(false) {
73 if (framebuffer.m_Terminal < 0) {
77 const sigset_t signals = terminalSignals();
78 m_Masked = sigprocmask(SIG_BLOCK, &signals, &m_PreviousMask) == 0;
79 m_Active = m_Masked && framebuffer.m_TerminalActive;
82Framebuffer::FrameGuard::~FrameGuard() {
84 sigprocmask(SIG_SETMASK, &m_PreviousMask,
nullptr);
89 if (m_Terminal >= 0) {
92 if (terminalFramebuffer) {
95 int terminal = open(
"/dev/tty0", O_RDWR | O_NOCTTY | O_CLOEXEC);
100 if (ioctl(terminal, VT_GETSTATE, &state) < 0 || !state.v_active) {
104 const unsigned number = state.v_active;
107 snprintf(path,
sizeof(path),
"/dev/tty%u", number);
108 terminal = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
112 if (ioctl(terminal, VT_GETMODE, &m_PreviousTerminalMode) < 0 ||
113 m_PreviousTerminalMode.mode != VT_AUTO ||
114 ioctl(terminal, KDGETMODE, &m_PreviousDisplayMode) < 0) {
118 const sigset_t signals = terminalSignals();
119 if (sigprocmask(SIG_BLOCK, &signals, &m_PreviousTerminalMask) < 0) {
123 struct sigaction action = {};
124 action.sa_handler = terminalSignal;
125 action.sa_mask = signals;
126 if (sigaction(SIGUSR1, &action, &m_PreviousReleaseAction) < 0) {
128 sigprocmask(SIG_SETMASK, &m_PreviousTerminalMask,
nullptr);
131 if (sigaction(SIGUSR2, &action, &m_PreviousAcquireAction) < 0) {
132 sigaction(SIGUSR1, &m_PreviousReleaseAction,
nullptr);
134 sigprocmask(SIG_SETMASK, &m_PreviousTerminalMask,
nullptr);
137 m_Terminal = terminal;
138 terminalFramebuffer =
this;
140 mode.mode = VT_PROCESS;
141 mode.relsig = SIGUSR1;
142 mode.acqsig = SIGUSR2;
143 if (ioctl(terminal, VT_SETMODE, &mode) < 0 || ioctl(terminal, KDSETMODE, KD_GRAPHICS) < 0 ||
144 ioctl(terminal, VT_GETSTATE, &state) < 0) {
148 m_TerminalActive = state.v_active == number;
149 sigprocmask(SIG_UNBLOCK, &signals,
nullptr);
153void Framebuffer::terminalSignal(
int signal) {
154 const int previousError = errno;
157 if (signal == SIGUSR1) {
158 framebuffer->m_TerminalActive = 0;
159 if (ioctl(framebuffer->m_Terminal, VT_RELDISP, 1) < 0) {
160 framebuffer->m_TerminalActive = 1;
162 }
else if (signal == SIGUSR2) {
163 if (ioctl(framebuffer->m_Terminal, VT_RELDISP, VT_ACKACQ) == 0) {
164 framebuffer->m_TerminalActive = 1;
165 framebuffer->m_TerminalRedraw = 1;
169 errno = previousError;
174 const bool redraw = guard && m_TerminalRedraw;
176 m_TerminalRedraw = 0;
181void Framebuffer::releaseTerminal() {
182 if (m_Terminal < 0) {
185 const sigset_t signals = terminalSignals();
187 sigprocmask(SIG_BLOCK, &signals, &mask);
188 ioctl(m_Terminal, KDSETMODE, m_PreviousDisplayMode);
189 ioctl(m_Terminal, VT_SETMODE, &m_PreviousTerminalMode);
192 const timespec timeout = {};
193 while (sigtimedwait(&signals,
nullptr, &timeout) >= 0) {
195 terminalFramebuffer =
nullptr;
196 sigaction(SIGUSR1, &m_PreviousReleaseAction,
nullptr);
197 sigaction(SIGUSR2, &m_PreviousAcquireAction,
nullptr);
200 const int notifications[] = {SIGUSR1, SIGUSR2};
201 for (
const int signal : notifications) {
202 if (sigismember(&m_PreviousTerminalMask, signal)) {
203 sigaddset(&mask, signal);
205 sigdelset(&mask, signal);
208 sigprocmask(SIG_SETMASK, &mask,
nullptr);
213 m_Fb = open(
"/dev/fb", O_RDWR);
215 pedigree_log(LOG_INFO,
"libfb: no framebuffer device");
216 fprintf(stderr,
"libfb: couldn't open framebuffer device");
229 int result = ioctl(m_Fb, PEDIGREE_FB_GETMODE, ¤t_mode);
231 m_bStoredMode =
true;
232 m_StoredMode = current_mode;
241 pedigree_fb_modeset old_mode = {m_StoredMode.width, m_StoredMode.height, m_StoredMode.depth};
242 ioctl(m_Fb, PEDIGREE_FB_SETMODE, &old_mode);
244 m_bStoredMode =
false;
252 if (!set_mode.width || !set_mode.height || !set_mode.depth) {
253 pedigree_log(LOG_INFO,
"libfb: current mode is not a graphics mode");
257 m_Width = set_mode.width;
258 m_Height = set_mode.height;
260 m_Format = CAIRO_FORMAT_ARGB32;
261 if (set_mode.format == PEDIGREE_FB_FORMAT_RGB24) {
262 if (set_mode.bytes_per_pixel != 4) {
264 "libfb: error: incompatible framebuffer format (bytes "
268 }
else if (set_mode.format == PEDIGREE_FB_FORMAT_RGB565) {
269 m_Format = CAIRO_FORMAT_RGB16_565;
270 }
else if (set_mode.format > PEDIGREE_FB_FORMAT_RGB32) {
272 "libfb: error: incompatible framebuffer format (possibly "
273 "BGR or similar)\n");
277 const size_t minimumStride = cairo_format_stride_for_width(m_Format, set_mode.width);
278 const size_t stride = set_mode.bytes_per_line ? set_mode.bytes_per_line : minimumStride;
279 if (stride < minimumStride || set_mode.height > SIZE_MAX / stride) {
280 pedigree_log(LOG_CRIT,
"libfb: invalid framebuffer stride");
285 pedigree_log(LOG_INFO,
"Mapping /dev/fb in (sz=%zx)...", stride * set_mode.height);
286 m_pFramebuffer = mmap(0, stride * set_mode.height, PROT_READ | PROT_WRITE, MAP_SHARED, m_Fb, 0);
287 pedigree_log(LOG_INFO,
"Got %p...", m_pFramebuffer);
289 if (m_pFramebuffer == MAP_FAILED) {
291 pedigree_log(LOG_CRIT,
"libfb: couldn't map framebuffer into address space");
294 pedigree_log(LOG_INFO,
"libfb: mapped framebuffer at %p", m_pFramebuffer);
297 m_FramebufferSize = stride * set_mode.height;
298 m_BytesPerLine = stride;
308 if (ioctl(m_Fb, PEDIGREE_FB_GETMODE, ¤t_mode) < 0) {
309 pedigree_log(LOG_INFO,
"libfb: can't get current mode info");
313 return mapMode(current_mode);
323 int result = ioctl(m_Fb, PEDIGREE_FB_SETMODE, &mode);
329 pedigree_log(LOG_INFO,
"libfb: can't set the desired mode");
330 fprintf(stderr,
"libfb: could not set desired mode (%zux%zu) in any colour depth.\n",
331 mode.width, mode.height);
336 result = ioctl(m_Fb, PEDIGREE_FB_GETMODE, &set_mode);
338 pedigree_log(LOG_INFO,
"libfb: can't get mode info");
339 fprintf(stderr,
"libfb: could not get mode information after setting mode.\n");
342 memset(&mode, 0,
sizeof(mode));
343 ioctl(m_Fb, PEDIGREE_FB_SETMODE, &mode);
347 return mapMode(set_mode);
353 ioctl(m_Fb, PEDIGREE_FB_REDRAW, &fbdirty);
void flush(size_t x, size_t y, size_t w, size_t h)
int enterMode(size_t desiredW, size_t desiredH, size_t desiredBpp)
void redraw(size_t x=~0UL, size_t y=~0UL, size_t w=~0UL, size_t h=~0UL, bool bChild=false)
All zeroes = 'revert to text mode'.